VBoxGuestR3LibDragAndDrop.cpp revision 2ad9f8a731c73f6ac74044d42d47bbaf6f44a566
/* $Id$ */
/** @file
* VBoxGuestR3Lib - Ring-3 Support Library for VirtualBox guest additions, Drag & Drop.
*/
/*
* Copyright (C) 2011-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
* VirtualBox OSE distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#ifdef LOG_GROUP
#endif
#define LOG_GROUP LOG_GROUP_GUEST_DND
#include "VBGLR3Internal.h"
/* Here all the communication with the host over HGCM is handled platform
* neutral. Also the receiving of URIs content (directory trees and files) is
* done here. So the platform code of the guests, should not take care of that.
*
* Todo:
* - Maybe the EOL converting of text MIME types (not fully sure, eventually
* better done on the host side)
*/
/******************************************************************************
* Private internal functions *
******************************************************************************/
static int vbglR3DnDQueryNextHostMessageType(uint32_t uClientId, uint32_t *puMsg, uint32_t *pcParms, bool fWait)
{
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
}
}
return rc;
}
char *pszFormats,
{
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
}
}
return rc;
}
{
if (RT_SUCCESS(rc))
return rc;
}
{
if (RT_SUCCESS(rc))
return rc;
}
char *pszDirname,
{
if (RT_SUCCESS(rc))
{
{
}
}
return rc;
}
char *pszFilename,
void *pvData,
{
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
}
}
return rc;
}
char *pszFormat,
void **ppvData,
{
if (!*pcbDataRecv)
return VERR_INVALID_PARAMETER;
/* Allocate temp buffer. */
if (!pvTmpData)
return VERR_NO_MEMORY;
/* Create and query the (unique) drop target directory. */
char pszDropDir[RTPATH_MAX];
if (RT_FAILURE(rc))
{
return rc;
}
/* Patch the old drop data with the new drop directory, so the drop target
* can find the files. */
0 /* fFlags */);
if (RT_SUCCESS(rc))
{
/* Cleanup the old data and write the new data back to the event. */
}
/* Lists for holding created files & directories
* in the case of a rollback. */
char szPathName[RTPATH_MAX];
uint32_t cbPathName = 0;
while (fLoop)
{
if (RT_SUCCESS(rc))
{
switch (uNextMsg)
{
{
sizeof(szPathName),
&fMode);
#ifdef DEBUG_andy
LogFlowFunc(("HOST_DND_HG_SND_DIR pszPathName=%s, cbPathName=%RU32, fMode=0x%x, rc=%Rrc\n",
#endif
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
{
if (pszNewDir)
{
}
else
rc = VERR_NO_MEMORY;
}
break;
}
{
sizeof(szPathName),
&fMode);
#ifdef DEBUG_andy
LogFlowFunc(("HOST_DND_HG_SND_FILE pszPathName=%s, cbPathName=%RU32, pvData=0x%p, cbDataRecv=%RU32, fMode=0x%x, rc=%Rrc\n",
#endif
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
{
if (pszPathAbs)
{
/** @todo r=andy Keep the file open and locked during the actual file transfer. Otherwise this will
* create all sorts of funny races because we don't know if the guest has
* modified the file in between the file data send calls. */
if (RT_SUCCESS(rc))
{
/** @todo r=andy Not very safe to assume that we were last appending to the current file. */
if (RT_SUCCESS(rc))
{
/* Valid UNIX mode? */
if ( RT_SUCCESS(rc)
&& (fMode & RTFS_UNIX_MASK))
}
}
#ifdef DEBUG
else
#endif
}
else
rc = VERR_NO_MEMORY;
}
break;
}
{
if (RT_SUCCESS(rc))
rc = VERR_CANCELLED;
/* Break out of the loop. */
}
default:
fLoop = false;
break;
}
}
else
{
if (rc == VERR_NO_DATA)
rc = VINF_SUCCESS;
break;
}
if (RT_FAILURE(rc))
break;
} /* while */
if (pvTmpData)
/* Cleanup on failure or if the user has canceled. */
if (RT_FAILURE(rc))
{
/* Remove any stuff created. */
}
return rc;
}
char *pszFormat,
void *pvData,
{
if (RT_SUCCESS(rc))
{
if ( RT_SUCCESS(rc)
|| rc == VERR_BUFFER_OVERFLOW)
{
}
}
return rc;
}
void *pvData,
{
if (RT_SUCCESS(rc))
{
if ( RT_SUCCESS(rc)
|| rc == VERR_BUFFER_OVERFLOW)
{
}
}
return rc;
}
char *pszFormat,
void **ppvData,
{
uint32_t cbDataRecv = 0;
*ppvData,
&cbDataRecv);
while (rc == VERR_BUFFER_OVERFLOW)
{
if (RT_SUCCESS(rc))
{
switch(uNextMsg)
{
{
if (!*ppvData)
{
rc = VERR_NO_MEMORY;
break;
}
&((char*)*ppvData)[cbAllDataRecv],
&cbDataRecv);
break;
}
default:
{
if (RT_SUCCESS(rc))
rc = VERR_CANCELLED;
break;
}
}
}
}
if (RT_SUCCESS(rc))
return rc;
}
char *pszFormat,
void **ppvData,
{
if (RT_SUCCESS(rc))
{
/* Check if this is an URI event. If so, let VbglR3 do all the actual
* the caller know.
*
* This keeps the actual (guest OS-)dependent client (like VBoxClient /
* VBoxTray) small by not having too much redundant code. */
}
return rc;
}
{
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
}
return rc;
}
char *pszFormat,
{
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
}
}
return rc;
}
/******************************************************************************
* Public functions *
******************************************************************************/
{
/* Initialize header */
/* Initialize parameter */
/* Do request */
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
}
return rc;
}
{
/* Do request */
if (RT_SUCCESS(rc))
return rc;
}
{
true /* fWait */);
if (RT_SUCCESS(rc))
{
switch(uMsg)
{
{
if (!pEvent->pszFormats)
rc = VERR_NO_MEMORY;
if (RT_SUCCESS(rc))
uMsg,
&pEvent->u.a.uDefAction,
&pEvent->u.a.uAllActions,
break;
}
{
break;
}
{
if (!pEvent->pszFormats)
rc = VERR_NO_MEMORY;
if (RT_SUCCESS(rc))
{
{
rc = VERR_NO_MEMORY;
}
}
if (RT_SUCCESS(rc))
break;
}
{
/* All messages in this case are handled internally
* by vbglR3DnDHGProcessSendDataMessage() and must
* be specified by a preceding HOST_DND_HG_SND_DATA call. */
break;
}
{
break;
}
#ifdef VBOX_WITH_DRAG_AND_DROP_GH
{
break;
}
{
if (!pEvent->pszFormats)
rc = VERR_NO_MEMORY;
if (RT_SUCCESS(rc))
&pEvent->u.a.uDefAction);
break;
}
#endif
default:
{
break;
}
}
}
return rc;
}
{
if (RT_SUCCESS(rc))
return rc;
}
{
if (RT_SUCCESS(rc))
return rc;
}
const char* pcszFormats)
{
if (RT_SUCCESS(rc))
return rc;
}
{
/* Total amount of bytes to send (including this data block). */
int rc;
{
if (RT_SUCCESS(rc))
if (RT_FAILURE(rc))
break;
cbSent += cbCurChunk;
}
if (RT_SUCCESS(rc))
LogFlowFunc(("Returning rc=%Rrc, cbData=%RU32, cbAddtionalData=%RU32\n",
return rc;
}
{
LogFlowFunc(("strDir=%s (%zu), fMode=0x%x\n",
if (RT_SUCCESS(rc))
return rc;
}
{
if (!pvBuf)
return VERR_NO_MEMORY;
LogFlowFunc(("strFile=%s (%zu), fMode=0x%x\n",
int rc = VINF_SUCCESS;
do
{
if (cbToRead)
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
}
if (RT_FAILURE(rc))
break;
} while (cbData);
return rc;
}
{
int rc;
{
case DnDURIObject::Directory:
break;
case DnDURIObject::File:
break;
default:
AssertMsgFailed(("Type %ld not implemented\n",
break;
}
return rc;
}
{
if (RT_SUCCESS(rc))
{
* URI list the host needs to know to initialize the drag'n drop operation. */
/* Include total bytes of all file paths,
* file sizes etc. */
lstURI.TotalBytes());
}
if (RT_SUCCESS(rc))
{
{
if (RT_FAILURE(rc))
break;
}
}
return rc;
}
const char *pszFormat,
{
int rc;
{
}
else
0 /* cbAdditionalData */);
if (RT_FAILURE(rc))
{
if (RT_SUCCESS(rc2))
}
return rc;
}
{
if (RT_SUCCESS(rc))
return rc;
}