diff --git a/client/Wayland/wlf_cliprdr.c b/client/Wayland/wlf_cliprdr.c index e2aea9661..c0fa78fc5 100644 --- a/client/Wayland/wlf_cliprdr.c +++ b/client/Wayland/wlf_cliprdr.c @@ -60,7 +60,6 @@ struct wlf_clipboard UwacSeat* seat; wClipboard* system; - wClipboardDelegate* delegate; size_t numClientFormats; CLIPRDR_FORMAT* clientFormats; @@ -767,193 +766,6 @@ wlf_cliprdr_server_format_data_response(CliprdrClientContext* context, return rc; } -static UINT -wlf_cliprdr_server_file_size_request(wfClipboard* clipboard, - const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) -{ - wClipboardFileSizeRequest request = { 0 }; - - WINPR_ASSERT(fileContentsRequest); - - request.streamId = fileContentsRequest->streamId; - request.listIndex = fileContentsRequest->listIndex; - - if (fileContentsRequest->cbRequested != sizeof(UINT64)) - { - WLog_Print(clipboard->log, WLOG_WARN, - "unexpected FILECONTENTS_SIZE request: %" PRIu32 " bytes", - fileContentsRequest->cbRequested); - } - - WINPR_ASSERT(clipboard); - WINPR_ASSERT(clipboard->delegate); - WINPR_ASSERT(clipboard->delegate->ClientRequestFileSize); - return clipboard->delegate->ClientRequestFileSize(clipboard->delegate, &request); -} - -static UINT -wlf_cliprdr_server_file_range_request(wfClipboard* clipboard, - const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) -{ - wClipboardFileRangeRequest request = { 0 }; - - WINPR_ASSERT(fileContentsRequest); - - request.streamId = fileContentsRequest->streamId; - request.listIndex = fileContentsRequest->listIndex; - request.nPositionLow = fileContentsRequest->nPositionLow; - request.nPositionHigh = fileContentsRequest->nPositionHigh; - request.cbRequested = fileContentsRequest->cbRequested; - - WINPR_ASSERT(clipboard); - WINPR_ASSERT(clipboard->delegate); - WINPR_ASSERT(clipboard->delegate->ClientRequestFileRange); - return clipboard->delegate->ClientRequestFileRange(clipboard->delegate, &request); -} - -static UINT -wlf_cliprdr_send_file_contents_failure(CliprdrClientContext* context, - const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) -{ - CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 }; - - WINPR_ASSERT(fileContentsRequest); - - response.common.msgFlags = CB_RESPONSE_FAIL; - response.streamId = fileContentsRequest->streamId; - - WINPR_ASSERT(context); - WINPR_ASSERT(context->ClientFileContentsResponse); - return context->ClientFileContentsResponse(context, &response); -} - -static UINT -wlf_cliprdr_server_file_contents_request(CliprdrClientContext* context, - const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) -{ - UINT error = NO_ERROR; - wfClipboard* clipboard; - - WINPR_ASSERT(context); - WINPR_ASSERT(fileContentsRequest); - - clipboard = context->custom; - WINPR_ASSERT(clipboard); - - /* - * MS-RDPECLIP 2.2.5.3 File Contents Request PDU (CLIPRDR_FILECONTENTS_REQUEST): - * The FILECONTENTS_SIZE and FILECONTENTS_RANGE flags MUST NOT be set at the same time. - */ - if ((fileContentsRequest->dwFlags & (FILECONTENTS_SIZE | FILECONTENTS_RANGE)) == - (FILECONTENTS_SIZE | FILECONTENTS_RANGE)) - { - WLog_Print(clipboard->log, WLOG_ERROR, "invalid CLIPRDR_FILECONTENTS_REQUEST.dwFlags"); - return wlf_cliprdr_send_file_contents_failure(context, fileContentsRequest); - } - - if (fileContentsRequest->dwFlags & FILECONTENTS_SIZE) - error = wlf_cliprdr_server_file_size_request(clipboard, fileContentsRequest); - - if (fileContentsRequest->dwFlags & FILECONTENTS_RANGE) - error = wlf_cliprdr_server_file_range_request(clipboard, fileContentsRequest); - - if (error) - { - WLog_Print(clipboard->log, WLOG_ERROR, - "failed to handle CLIPRDR_FILECONTENTS_REQUEST: 0x%08X", error); - return wlf_cliprdr_send_file_contents_failure(context, fileContentsRequest); - } - - return CHANNEL_RC_OK; -} - -static UINT wlf_cliprdr_clipboard_file_size_success(wClipboardDelegate* delegate, - const wClipboardFileSizeRequest* request, - UINT64 fileSize) -{ - CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 }; - wfClipboard* clipboard; - - WINPR_ASSERT(delegate); - WINPR_ASSERT(request); - - response.common.msgFlags = CB_RESPONSE_OK; - response.streamId = request->streamId; - response.cbRequested = sizeof(UINT64); - response.requestedData = (BYTE*)&fileSize; - - clipboard = delegate->custom; - WINPR_ASSERT(clipboard); - WINPR_ASSERT(clipboard->context); - WINPR_ASSERT(clipboard->context->ClientFileContentsResponse); - return clipboard->context->ClientFileContentsResponse(clipboard->context, &response); -} - -static UINT wlf_cliprdr_clipboard_file_size_failure(wClipboardDelegate* delegate, - const wClipboardFileSizeRequest* request, - UINT errorCode) -{ - CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 }; - wfClipboard* clipboard; - - WINPR_ASSERT(delegate); - WINPR_ASSERT(request); - WINPR_UNUSED(errorCode); - - response.common.msgFlags = CB_RESPONSE_FAIL; - response.streamId = request->streamId; - - clipboard = delegate->custom; - WINPR_ASSERT(clipboard); - WINPR_ASSERT(clipboard->context); - WINPR_ASSERT(clipboard->context->ClientFileContentsResponse); - return clipboard->context->ClientFileContentsResponse(clipboard->context, &response); -} - -static UINT wlf_cliprdr_clipboard_file_range_success(wClipboardDelegate* delegate, - const wClipboardFileRangeRequest* request, - const BYTE* data, UINT32 size) -{ - CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 }; - wfClipboard* clipboard; - - WINPR_ASSERT(delegate); - WINPR_ASSERT(request); - WINPR_ASSERT(data || (size == 0)); - - response.common.msgFlags = CB_RESPONSE_OK; - response.streamId = request->streamId; - response.cbRequested = size; - response.requestedData = (const BYTE*)data; - - clipboard = delegate->custom; - WINPR_ASSERT(clipboard); - WINPR_ASSERT(clipboard->context); - WINPR_ASSERT(clipboard->context->ClientFileContentsResponse); - return clipboard->context->ClientFileContentsResponse(clipboard->context, &response); -} - -static UINT wlf_cliprdr_clipboard_file_range_failure(wClipboardDelegate* delegate, - const wClipboardFileRangeRequest* request, - UINT errorCode) -{ - CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 }; - wfClipboard* clipboard; - - WINPR_ASSERT(delegate); - WINPR_ASSERT(request); - WINPR_UNUSED(errorCode); - - response.common.msgFlags = CB_RESPONSE_FAIL; - response.streamId = request->streamId; - - clipboard = delegate->custom; - WINPR_ASSERT(clipboard); - WINPR_ASSERT(clipboard->context); - WINPR_ASSERT(clipboard->context->ClientFileContentsResponse); - return clipboard->context->ClientFileContentsResponse(clipboard->context, &response); -} - wfClipboard* wlf_clipboard_new(wlfContext* wfc) { rdpChannels* channels; @@ -974,18 +786,6 @@ wfClipboard* wlf_clipboard_new(wlfContext* wfc) clipboard->system = ClipboardCreate(); if (!clipboard->system) goto fail; - - clipboard->delegate = ClipboardGetDelegate(clipboard->system); - if (!clipboard->delegate) - goto fail; - - clipboard->delegate->custom = clipboard; - /* TODO: set up a filesystem base path for local URI */ - /* clipboard->delegate->basePath = "file:///tmp/foo/bar/gaga"; */ - clipboard->delegate->ClipboardFileSizeSuccess = wlf_cliprdr_clipboard_file_size_success; - clipboard->delegate->ClipboardFileSizeFailure = wlf_cliprdr_clipboard_file_size_failure; - clipboard->delegate->ClipboardFileRangeSuccess = wlf_cliprdr_clipboard_file_range_success; - clipboard->delegate->ClipboardFileRangeFailure = wlf_cliprdr_clipboard_file_range_failure; return clipboard; fail: @@ -1022,8 +822,8 @@ BOOL wlf_cliprdr_init(wfClipboard* clipboard, CliprdrClientContext* cliprdr) cliprdr->ServerFormatList = wlf_cliprdr_server_format_list; cliprdr->ServerFormatListResponse = wlf_cliprdr_server_format_list_response; cliprdr->ServerFormatDataRequest = wlf_cliprdr_server_format_data_request; - cliprdr->ServerFormatDataResponse = wlf_cliprdr_server_format_data_response; - cliprdr->ServerFileContentsRequest = wlf_cliprdr_server_file_contents_request; + cliprdr->ServerFormatDataResponse = wlf_cliprdr_server_format_data_response; + return TRUE; } diff --git a/client/X11/xf_cliprdr.c b/client/X11/xf_cliprdr.c index 48058e91f..d92bb4c44 100644 --- a/client/X11/xf_cliprdr.c +++ b/client/X11/xf_cliprdr.c @@ -77,7 +77,6 @@ struct xf_clipboard CliprdrClientContext* context; wClipboard* system; - wClipboardDelegate* delegate; Window root_window; Atom clipboard_atom; @@ -1998,48 +1997,6 @@ xf_cliprdr_server_format_data_response(CliprdrClientContext* context, return CHANNEL_RC_OK; } -static UINT -xf_cliprdr_server_file_size_request(xfClipboard* clipboard, - const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) -{ - wClipboardFileSizeRequest request = { 0 }; - - WINPR_ASSERT(clipboard); - WINPR_ASSERT(fileContentsRequest); - - request.streamId = fileContentsRequest->streamId; - request.listIndex = fileContentsRequest->listIndex; - - if (fileContentsRequest->cbRequested != sizeof(UINT64)) - { - WLog_WARN(TAG, "unexpected FILECONTENTS_SIZE request: %" PRIu32 " bytes", - fileContentsRequest->cbRequested); - } - - WINPR_ASSERT(clipboard->delegate); - WINPR_ASSERT(clipboard->delegate->ClientRequestFileSize); - return clipboard->delegate->ClientRequestFileSize(clipboard->delegate, &request); -} - -static UINT -xf_cliprdr_server_file_range_request(xfClipboard* clipboard, - const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) -{ - wClipboardFileRangeRequest request = { 0 }; - - WINPR_ASSERT(fileContentsRequest); - - request.streamId = fileContentsRequest->streamId; - request.listIndex = fileContentsRequest->listIndex; - request.nPositionLow = fileContentsRequest->nPositionLow; - request.nPositionHigh = fileContentsRequest->nPositionHigh; - request.cbRequested = fileContentsRequest->cbRequested; - - WINPR_ASSERT(clipboard); - WINPR_ASSERT(clipboard->delegate); - WINPR_ASSERT(clipboard->delegate->ClientRequestFileRange); - return clipboard->delegate->ClientRequestFileRange(clipboard->delegate, &request); -} static UINT xf_cliprdr_send_file_contents_failure(CliprdrClientContext* context, @@ -2096,92 +2053,6 @@ xf_cliprdr_server_file_contents_request(CliprdrClientContext* context, return CHANNEL_RC_OK; } -static UINT xf_cliprdr_clipboard_file_size_success(wClipboardDelegate* delegate, - const wClipboardFileSizeRequest* request, - UINT64 fileSize) -{ - CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 }; - xfClipboard* clipboard; - - WINPR_ASSERT(delegate); - WINPR_ASSERT(request); - - response.common.msgFlags = CB_RESPONSE_OK; - response.streamId = request->streamId; - response.cbRequested = sizeof(UINT64); - response.requestedData = (BYTE*)&fileSize; - - clipboard = delegate->custom; - WINPR_ASSERT(clipboard); - WINPR_ASSERT(clipboard->context); - WINPR_ASSERT(clipboard->context->ClientFileContentsResponse); - return clipboard->context->ClientFileContentsResponse(clipboard->context, &response); -} - -static UINT xf_cliprdr_clipboard_file_size_failure(wClipboardDelegate* delegate, - const wClipboardFileSizeRequest* request, - UINT errorCode) -{ - CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 }; - xfClipboard* clipboard; - - WINPR_ASSERT(delegate); - WINPR_ASSERT(request); - WINPR_UNUSED(errorCode); - - response.common.msgFlags = CB_RESPONSE_FAIL; - response.streamId = request->streamId; - - clipboard = delegate->custom; - WINPR_ASSERT(clipboard); - WINPR_ASSERT(clipboard->context); - WINPR_ASSERT(clipboard->context->ClientFileContentsResponse); - return clipboard->context->ClientFileContentsResponse(clipboard->context, &response); -} - -static UINT xf_cliprdr_clipboard_file_range_success(wClipboardDelegate* delegate, - const wClipboardFileRangeRequest* request, - const BYTE* data, UINT32 size) -{ - CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 }; - xfClipboard* clipboard; - - WINPR_ASSERT(delegate); - WINPR_ASSERT(request); - - response.common.msgFlags = CB_RESPONSE_OK; - response.streamId = request->streamId; - response.cbRequested = size; - response.requestedData = (const BYTE*)data; - - clipboard = delegate->custom; - WINPR_ASSERT(clipboard); - WINPR_ASSERT(clipboard->context); - WINPR_ASSERT(clipboard->context->ClientFileContentsResponse); - return clipboard->context->ClientFileContentsResponse(clipboard->context, &response); -} - -static UINT xf_cliprdr_clipboard_file_range_failure(wClipboardDelegate* delegate, - const wClipboardFileRangeRequest* request, - UINT errorCode) -{ - CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 }; - xfClipboard* clipboard; - - WINPR_ASSERT(delegate); - WINPR_ASSERT(request); - WINPR_UNUSED(errorCode); - - response.common.msgFlags = CB_RESPONSE_FAIL; - response.streamId = request->streamId; - - clipboard = delegate->custom; - WINPR_ASSERT(clipboard); - WINPR_ASSERT(clipboard->context); - WINPR_ASSERT(clipboard->context->ClientFileContentsResponse); - return clipboard->context->ClientFileContentsResponse(clipboard->context, &response); -} - static BOOL xf_cliprdr_clipboard_is_valid_unix_filename(LPCWSTR filename) { LPCWSTR c; @@ -2372,24 +2243,11 @@ xfClipboard* xf_clipboard_new(xfContext* xfc, BOOL relieveFilenameRestriction) clipboard->targets[0] = XInternAtom(xfc->display, "TIMESTAMP", FALSE); clipboard->targets[1] = XInternAtom(xfc->display, "TARGETS", FALSE); clipboard->numTargets = 2; - clipboard->incr_atom = XInternAtom(xfc->display, "INCR", FALSE); - clipboard->delegate = ClipboardGetDelegate(clipboard->system); - clipboard->delegate->custom = clipboard; + clipboard->incr_atom = XInternAtom(xfc->display, "INCR", FALSE); clipboard->file = cliprdr_file_context_new(clipboard); if (!clipboard->file) - goto fail; - clipboard->delegate->basePath = cliprdr_file_context_base_path(clipboard->file); - clipboard->delegate->ClipboardFileSizeSuccess = xf_cliprdr_clipboard_file_size_success; - clipboard->delegate->ClipboardFileSizeFailure = xf_cliprdr_clipboard_file_size_failure; - clipboard->delegate->ClipboardFileRangeSuccess = xf_cliprdr_clipboard_file_range_success; - clipboard->delegate->ClipboardFileRangeFailure = xf_cliprdr_clipboard_file_range_failure; - - if (relieveFilenameRestriction) - { - WLog_DBG(TAG, "Relieving CLIPRDR filename restriction"); - clipboard->delegate->IsFileNameComponentValid = xf_cliprdr_clipboard_is_valid_unix_filename; - } + goto fail; return clipboard; diff --git a/client/X11/xf_cliprdr_file.c b/client/X11/xf_cliprdr_file.c index c5b8e2e59..1a8a6ab62 100644 --- a/client/X11/xf_cliprdr_file.c +++ b/client/X11/xf_cliprdr_file.c @@ -621,136 +621,7 @@ static DWORD WINAPI cliprdr_file_fuse_thread(LPVOID arg) ExitThread(0); return 0; } -#endif -void cliprdr_file_session_terminate(CliprdrFileContext* file) -{ - if (!file) - return; - -#if defined(WITH_FUSE2) || defined(WITH_FUSE3) - if (file->fuse_sess) - fuse_session_exit(file->fuse_sess); -#endif - /* not elegant but works for umounting FUSE - fuse_chan must receieve a oper buf to unblock fuse_session_receive_buf function. - */ - winpr_PathFileExists(file->path); -} - -void cliprdr_file_context_free(CliprdrFileContext* file) -{ - if (!file) - return; - -#if defined(WITH_FUSE2) || defined(WITH_FUSE3) - if (file->fuse_thread) - { - cliprdr_file_session_terminate(file); - WaitForSingleObject(file->fuse_thread, INFINITE); - CloseHandle(file->fuse_thread); - } - - // fuse related - ArrayList_Free(file->stream_list); - ArrayList_Free(file->ino_list); -#endif - winpr_RemoveDirectory(file->path); - free(file->path); - free(file); -} - -static BOOL create_base_path(CliprdrFileContext* file) -{ - WINPR_ASSERT(file); - - char base[64] = { 0 }; - _snprintf(base, sizeof(base), "/.xfreerdp.cliprdr.%" PRIu32, GetCurrentProcessId()); - - file->path = GetKnownSubPath(KNOWN_PATH_TEMP, base); - if (!file->path) - return FALSE; - - if (!winpr_PathFileExists(file->path) && !winpr_PathMakePath(file->path, 0)) - { - WLog_ERR(TAG, "Failed to create directory '%s'", file->path); - return FALSE; - } - return TRUE; -} - -CliprdrFileContext* cliprdr_file_context_new(void* context) -{ - CliprdrFileContext* file = calloc(1, sizeof(CliprdrFileContext)); - if (!file) - return NULL; - - file->clipboard = context; - if (!create_base_path(file)) - goto fail; - -#if defined(WITH_FUSE2) || defined(WITH_FUSE3) - file->current_stream_id = 0; - file->stream_list = ArrayList_New(TRUE); - if (!file->stream_list) - { - WLog_ERR(TAG, "failed to allocate stream_list"); - goto fail; - } - wObject* obj = ArrayList_Object(file->stream_list); - obj->fnObjectFree = free; - - file->ino_list = ArrayList_New(TRUE); - if (!file->ino_list) - { - WLog_ERR(TAG, "failed to allocate stream_list"); - goto fail; - } - obj = ArrayList_Object(file->ino_list); - obj->fnObjectFree = cliprdr_file_fuse_inode_free; - - if (!xf_fuse_repopulate(file->ino_list)) - goto fail; - - if (!(file->fuse_thread = CreateThread(NULL, 0, cliprdr_file_fuse_thread, file, 0, NULL))) - { - goto fail; - } -#endif - return file; - -fail: - cliprdr_file_context_free(file); - return NULL; -} - -BOOL cliprdr_file_context_clear(CliprdrFileContext* file) -{ -#if defined(WITH_FUSE2) || defined(WITH_FUSE3) - if (file->stream_list) - { - size_t index; - size_t count; - CliprdrFuseStream* stream; - ArrayList_Lock(file->stream_list); - file->current_stream_id = 0; - /* reply error to all req first don't care request type*/ - count = ArrayList_Count(file->stream_list); - for (index = 0; index < count; index++) - { - stream = (CliprdrFuseStream*)ArrayList_GetItem(file->stream_list, index); - fuse_reply_err(stream->req, EIO); - } - ArrayList_Unlock(file->stream_list); - - ArrayList_Clear(file->stream_list); - } - - xf_fuse_repopulate(file->ino_list); -#endif -} - -#if defined(WITH_FUSE2) || defined(WITH_FUSE3) static CliprdrFuseInode* cliprdr_file_fuse_create_root_node(void) { CliprdrFuseInode* rootNode = (CliprdrFuseInode*)calloc(1, sizeof(CliprdrFuseInode)); @@ -1235,3 +1106,130 @@ const char* cliprdr_file_context_base_path(CliprdrFileContext* file) WINPR_ASSERT(file); return file->path; } + +void cliprdr_file_session_terminate(CliprdrFileContext* file) +{ + if (!file) + return; + +#if defined(WITH_FUSE2) || defined(WITH_FUSE3) + if (file->fuse_sess) + fuse_session_exit(file->fuse_sess); +#endif + /* not elegant but works for umounting FUSE + fuse_chan must receieve a oper buf to unblock fuse_session_receive_buf function. + */ + winpr_PathFileExists(file->path); +} + +void cliprdr_file_context_free(CliprdrFileContext* file) +{ + if (!file) + return; + +#if defined(WITH_FUSE2) || defined(WITH_FUSE3) + if (file->fuse_thread) + { + cliprdr_file_session_terminate(file); + WaitForSingleObject(file->fuse_thread, INFINITE); + CloseHandle(file->fuse_thread); + } + + // fuse related + ArrayList_Free(file->stream_list); + ArrayList_Free(file->ino_list); +#endif + winpr_RemoveDirectory(file->path); + free(file->path); + free(file); +} + +static BOOL create_base_path(CliprdrFileContext* file) +{ + WINPR_ASSERT(file); + + char base[64] = { 0 }; + _snprintf(base, sizeof(base), "/.xfreerdp.cliprdr.%" PRIu32, GetCurrentProcessId()); + + file->path = GetKnownSubPath(KNOWN_PATH_TEMP, base); + if (!file->path) + return FALSE; + + if (!winpr_PathFileExists(file->path) && !winpr_PathMakePath(file->path, 0)) + { + WLog_ERR(TAG, "Failed to create directory '%s'", file->path); + return FALSE; + } + return TRUE; +} + +CliprdrFileContext* cliprdr_file_context_new(void* context) +{ + CliprdrFileContext* file = calloc(1, sizeof(CliprdrFileContext)); + if (!file) + return NULL; + + file->clipboard = context; + if (!create_base_path(file)) + goto fail; + +#if defined(WITH_FUSE2) || defined(WITH_FUSE3) + file->current_stream_id = 0; + file->stream_list = ArrayList_New(TRUE); + if (!file->stream_list) + { + WLog_ERR(TAG, "failed to allocate stream_list"); + goto fail; + } + wObject* obj = ArrayList_Object(file->stream_list); + obj->fnObjectFree = free; + + file->ino_list = ArrayList_New(TRUE); + if (!file->ino_list) + { + WLog_ERR(TAG, "failed to allocate stream_list"); + goto fail; + } + obj = ArrayList_Object(file->ino_list); + obj->fnObjectFree = cliprdr_file_fuse_inode_free; + + if (!xf_fuse_repopulate(file->ino_list)) + goto fail; + + if (!(file->fuse_thread = CreateThread(NULL, 0, cliprdr_file_fuse_thread, file, 0, NULL))) + { + goto fail; + } +#endif + return file; + +fail: + cliprdr_file_context_free(file); + return NULL; +} + +BOOL cliprdr_file_context_clear(CliprdrFileContext* file) +{ +#if defined(WITH_FUSE2) || defined(WITH_FUSE3) + if (file->stream_list) + { + size_t index; + size_t count; + CliprdrFuseStream* stream; + ArrayList_Lock(file->stream_list); + file->current_stream_id = 0; + /* reply error to all req first don't care request type*/ + count = ArrayList_Count(file->stream_list); + for (index = 0; index < count; index++) + { + stream = (CliprdrFuseStream*)ArrayList_GetItem(file->stream_list, index); + fuse_reply_err(stream->req, EIO); + } + ArrayList_Unlock(file->stream_list); + + ArrayList_Clear(file->stream_list); + } + + xf_fuse_repopulate(file->ino_list); +#endif +}