Changeset 38085 in vbox
- Timestamp:
- Jul 21, 2011 7:29:54 AM (14 years ago)
- svn:sync-xref-src-repo-rev:
- 73032
- Location:
- trunk
- Files:
-
- 2 added
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/doc/manual/en_US/user_VBoxManage.xml
r38055 r38085 2880 2880 2881 2881 <listitem> 2882 <para><computeroutput>stat</computeroutput>, which displays file 2883 or file system status on the guest.</para> 2884 2885 <screen>VBoxManage guestcontrol <vmname>|<uuid> stat 2886 <file element(s) to check on guest> 2887 [--username "<name>"] [--password "<password>"] 2888 [--verbose]</screen> 2889 2890 <para>where the parameters mean: <glosslist> 2891 <glossentry> 2892 <glossterm>uuid|vmname</glossterm> 2893 2894 <glossdef> 2895 <para>The VM UUID or VM name. Mandatory.</para> 2896 </glossdef> 2897 </glossentry> 2898 2899 <glossentry> 2900 <glossterm>file element(s) to check on guest</glossterm> 2901 2902 <glossdef> 2903 <para>Absolute path of directory/directories to check on 2904 guest, e.g. <computeroutput>/home/foo/a.out</computeroutput>. 2905 The specified user must have appropriate rights to access 2906 the given file element(s).</para> 2907 </glossdef> 2908 </glossentry> 2909 2910 <glossentry> 2911 <glossterm>--username <name></glossterm> 2912 2913 <glossdef> 2914 <para>Name of the user the copy process should run under. 2915 This user must exist on the guest OS.</para> 2916 </glossdef> 2917 </glossentry> 2918 2919 <glossentry> 2920 <glossterm>--password <password></glossterm> 2921 2922 <glossdef> 2923 <para>Password of the user account specified with 2924 <computeroutput>--username</computeroutput>. If not given, 2925 an empty password is assumed.</para> 2926 </glossdef> 2927 </glossentry> 2928 2929 <glossentry> 2930 <glossterm>--verbose</glossterm> 2931 2932 <glossdef> 2933 <para>Tells VBoxManage to be more verbose.</para> 2934 </glossdef> 2935 </glossentry> 2936 </glosslist></para> 2937 </listitem> 2938 2939 <listitem> 2882 2940 <para><computeroutput>updateadditions</computeroutput>, which allows 2883 2941 for updating an already installed Guest Additions version on the -
trunk/include/VBox/HostServices/GuestControlSvc.h
r37375 r38085 88 88 */ 89 89 #define VBOXSERVICE_TOOL_CAT "vbox_cat" 90 #define VBOXSERVICE_TOOL_LS "vbox_ls" 90 91 #define VBOXSERVICE_TOOL_MKDIR "vbox_mkdir" 92 #define VBOXSERVICE_TOOL_STAT "vbox_stat" 91 93 /** @} */ 92 94 -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlExec.cpp
r37816 r38085 1273 1273 { 1274 1274 fPendingClose = true; 1275 VBoxServiceVerbose(4, "ControlExec: Got last input block (PID %u) of size %u ...\n", uPID, cbSize); 1275 VBoxServiceVerbose(4, "ControlExec: Got last input block (PID %u) of size %u ...\n", 1276 uPID, cbSize); 1276 1277 } 1277 1278 … … 1319 1320 uStatus, uFlags, (uint32_t)cbWritten); 1320 1321 1321 VBoxServiceVerbose(3, "ControlExec: VBoxServiceControlExecHandleCmdSetInput returned with %Rrc\n", rc); 1322 if (RT_FAILURE(rc)) 1323 VBoxServiceError("ControlExec: Failed to report input status! Error: %Rrc\n", rc); 1322 1324 return rc; 1323 1325 } … … 1351 1353 if (RT_SUCCESS(rc)) 1352 1354 { 1355 VBoxServiceVerbose(3, "ControlExec: Got output (PID %u), read=%u, handle=%u, flags=%u\n", 1356 uPID, cbRead, uHandleID, uFlags); 1357 1353 1358 /* Note: Since the context ID is unique the request *has* to be completed here, 1354 1359 * regardless whether we got data or not! Otherwise the progress object … … 1358 1363 pBuf, cbRead); 1359 1364 } 1365 else 1366 VBoxServiceError("ControlExec: Failed to retrieve output (PID %u), rc=%Rrc\n", 1367 uPID, rc); 1360 1368 RTMemFree(pBuf); 1361 1369 } … … 1365 1373 else 1366 1374 VBoxServiceError("ControlExec: Failed to retrieve exec output command! Error: %Rrc\n", rc); 1367 VBoxServiceVerbose(3, "ControlExec: VBoxServiceControlExecHandleCmdGetOutput returned with %Rrc\n", rc); 1368 return rc; 1369 } 1370 1375 return rc; 1376 } 1377 -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlExecThread.cpp
r36887 r38085 273 273 uint8_t *pBuf, uint32_t cbSize, uint32_t *pcbRead) 274 274 { 275 AssertPtrReturn(pBuf, VERR_INVALID_PARAMETER); 275 AssertPtrReturn(pBuf, VERR_INVALID_POINTER); 276 AssertReturn(cbSize, VERR_INVALID_PARAMETER); 276 277 277 278 int rc = RTCritSectEnter(&g_GuestControlExecThreadsCritSect); -
trunk/src/VBox/Additions/common/VBoxService/VBoxServicePipeBuf.cpp
r36880 r38085 112 112 AssertRC(rc); 113 113 } 114 115 #ifdef DEBUG_andy 116 VBoxServiceVerbose(4, "PipeBuf[0x%p]: read=%u, size=%u, alloc=%u, off=%u\n", 117 pBuf, *pcbToRead, pBuf->cbSize, pBuf->cbAllocated, pBuf->cbOffset); 118 #endif 114 119 } 115 120 else … … 269 274 AssertRC(rc); 270 275 } 276 277 #ifdef DEBUG_andy 278 VBoxServiceVerbose(4, "PipeBuf[0x%p]: written=%u, size=%u, alloc=%u, off=%u\n", 279 pBuf, cbData, pBuf->cbSize, pBuf->cbAllocated, pBuf->cbOffset); 280 #endif 271 281 } 272 282 } -
trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
r37761 r38085 69 69 static volatile bool g_fGuestCtrlCanceled = false; 70 70 71 typedef struct COPYCONTEXT 72 { 73 IGuest *pGuest; 74 bool fVerbose; 75 bool fHostToGuest; 76 char *pszUsername; 77 char *pszPassword; 78 } COPYCONTEXT, *PCOPYCONTEXT; 79 71 80 /** 72 81 * An entry for a source element, including an optional filter. … … 100 109 101 110 /** 102 * An entry for an element which needs to be copied tothe guest.111 * An entry for an element which needs to be copied/created to/on the guest. 103 112 */ 104 113 typedef struct DESTFILEENTRY … … 187 196 " [--timeout <msec>] [--unix2dos] [--verbose]\n" 188 197 " [--wait-exit] [--wait-stdout] [--wait-stderr]\n" 189 //" [--output-format=<dos>|<unix>]\n"190 " [--output-type=<binary>|<text>]\n"191 198 " [-- [<argument1>] ... [<argumentN>]]\n" 192 199 /** @todo Add a "--" parameter (has to be last parameter) to directly execute 193 200 * stuff, e.g. "VBoxManage guestcontrol execute <VMName> --username <> ... -- /bin/rm -Rf /foo". */ 194 201 "\n" 195 #if 0196 202 " copyfrom\n" 197 203 " <source on guest> <destination on host>\n" … … 199 205 " [--dryrun] [--follow] [--recursive] [--verbose]\n" 200 206 "\n" 201 #endif202 207 " copyto|cp\n" 203 208 " <source on host> <destination on guest>\n" … … 206 211 "\n" 207 212 " createdir[ectory]|mkdir|md\n" 208 " <director yto create on guest>\n"213 " <director[y|ies] to create on guest>\n" 209 214 " --username <name> --password <password>\n" 210 215 " [--parents] [--mode <mode>] [--verbose]\n" 216 "\n" 217 " stat\n" 218 " <file element(s) to check on guest>\n" 219 " --username <name> --password <password>\n" 220 " [--verbose]\n" 211 221 "\n" 212 222 " updateadditions\n" … … 572 582 if (Utf8UserName.isEmpty()) 573 583 return errorSyntax(USAGE_GUESTCONTROL, "No user name specified!"); 584 585 /* Any output conversion not supported yet! */ 586 if (eOutputType != OUTPUTTYPE_UNDEFINED) 587 return errorSyntax(USAGE_GUESTCONTROL, "Output conversion not implemented yet!"); 574 588 575 589 /* … … 685 699 * generic problem and the new VFS APIs will handle it more 686 700 * transparently. (requires writing dos2unix/unix2dos filters ofc) */ 687 if (eOutputType != OUTPUTTYPE_UNDEFINED) 701 702 /* 703 * If aOutputData is text data from the guest process' stdout or stderr, 704 * it has a platform dependent line ending. So standardize on 705 * Unix style, as RTStrmWrite does the LF -> CR/LF replacement on 706 * Windows. Otherwise we end up with CR/CR/LF on Windows. 707 */ 708 ULONG cbOutputDataPrint = cbOutputData; 709 for (BYTE *s = aOutputData.raw(), *d = s; 710 s - aOutputData.raw() < (ssize_t)cbOutputData; 711 s++, d++) 688 712 { 689 /* 690 * If aOutputData is text data from the guest process' stdout or stderr, 691 * it has a platform dependent line ending. So standardize on 692 * Unix style, as RTStrmWrite does the LF -> CR/LF replacement on 693 * Windows. Otherwise we end up with CR/CR/LF on Windows. 694 */ 695 ULONG cbOutputDataPrint = cbOutputData; 696 for (BYTE *s = aOutputData.raw(), *d = s; 697 s - aOutputData.raw() < (ssize_t)cbOutputData; 698 s++, d++) 713 if (*s == '\r') 699 714 { 700 if (*s == '\r') 701 { 702 /* skip over CR, adjust destination */ 703 d--; 704 cbOutputDataPrint--; 705 } 706 else if (s != d) 707 *d = *s; 715 /* skip over CR, adjust destination */ 716 d--; 717 cbOutputDataPrint--; 708 718 } 709 RTStrmWrite(g_pStdOut, aOutputData.raw(), cbOutputDataPrint); 719 else if (s != d) 720 *d = *s; 710 721 } 711 else /* Just dump all data as we got it ... */ 712 RTStrmWrite(g_pStdOut, aOutputData.raw(), cbOutputData); 722 RTStrmWrite(g_pStdOut, aOutputData.raw(), cbOutputDataPrint); 713 723 } 714 724 } … … 790 800 } 791 801 792 /** @todo Clean up too long parameter list -> move guest specific stuff into own struct etc! */ 793 static int ctrlCopyDirectoryReadGuest(IGuest *pGuest, 794 const char *pszUsername, const char *pszPassword, 795 const char *pszRootDir, const char *pszSubDir, 796 const char *pszFilter, const char *pszDest, 797 uint32_t fFlags, uint32_t *pcObjects, DESTDIRMAP &dirMap) 798 { 799 AssertPtrReturn(pszRootDir, VERR_INVALID_POINTER); 802 static int ctrlCopyContextCreate(IGuest *pGuest, bool fVerbose, bool fHostToGuest, 803 const char *pszUsername, const char *pszPassword, 804 PCOPYCONTEXT *ppContext) 805 { 806 AssertPtrReturn(pGuest, VERR_INVALID_POINTER); 807 AssertPtrReturn(pszUsername, VERR_INVALID_POINTER); 808 AssertPtrReturn(pszPassword, VERR_INVALID_POINTER); 809 810 PCOPYCONTEXT pContext = (PCOPYCONTEXT)RTMemAlloc(sizeof(COPYCONTEXT)); 811 AssertPtrReturn(pContext, VERR_NO_MEMORY); 812 pContext->pGuest = pGuest; 813 pContext->fVerbose = fVerbose; 814 pContext->fHostToGuest = fHostToGuest; 815 816 pContext->pszUsername = RTStrDup(pszUsername); 817 if (!pContext->pszUsername) 818 { 819 RTMemFree(pContext); 820 return VERR_NO_MEMORY; 821 } 822 823 pContext->pszPassword = RTStrDup(pszPassword); 824 if (!pContext->pszPassword) 825 { 826 RTStrFree(pContext->pszUsername); 827 RTMemFree(pContext); 828 return VERR_NO_MEMORY; 829 } 830 831 *ppContext = pContext; 832 833 return VINF_SUCCESS; 834 } 835 836 static void ctrlCopyContextFree(PCOPYCONTEXT pContext) 837 { 838 if (pContext) 839 { 840 RTStrFree(pContext->pszUsername); 841 RTStrFree(pContext->pszPassword); 842 RTMemFree(pContext); 843 } 844 } 845 846 /* 847 * Source Dest Translated 848 * c:\foo.txt c:\from_host c:\from_host\foo.txt 849 * c:\asdf\foo c:\qwer c:\qwer\foo 850 * c:\bar\baz.txt d:\users\ d:\users\baz.txt 851 * c:\*.dll e:\baz e:\baz 852 */ 853 static int ctrlCopyTranslatePath(PCOPYCONTEXT pContext, 854 const char *pszSourceRoot, const char *pszSource, 855 const char *pszDest, char **ppszTranslated) 856 { 857 AssertPtrReturn(pContext, VERR_INVALID_POINTER); 858 AssertPtrReturn(pszSourceRoot, VERR_INVALID_POINTER); 859 AssertPtrReturn(pszSource, VERR_INVALID_POINTER); 860 AssertPtrReturn(pszDest, VERR_INVALID_POINTER); 861 AssertPtrReturn(ppszTranslated, VERR_INVALID_POINTER); 862 863 /* Source path must contain the source root! */ 864 if (!RTPathStartsWith(pszSource, pszSourceRoot)) 865 return VERR_INVALID_PARAMETER; 866 867 /* Construct the relative dest destination path by "subtracting" the 868 * source from the source root, e.g. 869 * 870 * source root path = "e:\foo\", source = "e:\foo\bar" 871 * dest = "d:\baz\" 872 * translated = "d:\baz\bar\" 873 */ 874 875 size_t lenRoot = strlen(pszSourceRoot); 876 AssertReturn(lenRoot, VERR_INVALID_PARAMETER); 877 char *pszTranslated = RTStrDup(pszDest); 878 AssertReturn(pszTranslated, VERR_NO_MEMORY); 879 int vrc = RTStrAAppend(&pszTranslated, &pszSource[lenRoot]); 880 if (RT_FAILURE(vrc)) 881 return vrc; 882 883 *ppszTranslated = pszTranslated; 884 885 #ifdef DEBUG 886 if (pContext->fVerbose) 887 RTPrintf("Translating root=%s, source=%s, dest=%s -> %s\n", 888 pszSourceRoot, pszSource, pszDest, *ppszTranslated); 889 #endif 890 891 return vrc; 892 } 893 894 static int ctrlCopyDirCreate(PCOPYCONTEXT pContext, const char *pszDir) 895 { 896 AssertPtrReturn(pContext, VERR_INVALID_POINTER); 897 AssertPtrReturn(pszDir, VERR_INVALID_POINTER); 898 899 int rc = VINF_SUCCESS; 900 if (pContext->fHostToGuest) /* We want to create directories on the guest. */ 901 { 902 HRESULT hrc = pContext->pGuest->DirectoryCreate(Bstr(pszDir).raw(), 903 Bstr(pContext->pszUsername).raw(), Bstr(pContext->pszPassword).raw(), 904 700, DirectoryCreateFlag_Parents); 905 if (FAILED(hrc)) 906 rc = ctrlPrintError(pContext->pGuest, COM_IIDOF(IGuest)); 907 } 908 else /* ... or on the host. */ 909 { 910 rc = RTDirCreate(pszDir, 700); 911 if (rc == VERR_ALREADY_EXISTS) 912 rc = VINF_SUCCESS; 913 } 914 return rc; 915 } 916 917 static int ctrlCopyDirExists(PCOPYCONTEXT pContext, bool bGuest, 918 const char *pszDir, bool *fExists) 919 { 920 AssertPtrReturn(pContext, false); 921 AssertPtrReturn(pszDir, false); 922 AssertPtrReturn(fExists, false); 923 924 int rc = VINF_SUCCESS; 925 if (bGuest) 926 { 927 BOOL fDirExists = FALSE; 928 HRESULT hr = pContext->pGuest->FileExists(Bstr(pszDir).raw(), 929 Bstr(pContext->pszUsername).raw(), 930 Bstr(pContext->pszPassword).raw(), &fDirExists); 931 if (FAILED(hr)) 932 rc = ctrlPrintError(pContext->pGuest, COM_IIDOF(IGuest)); 933 else 934 *fExists = fDirExists ? true : false; 935 } 936 else 937 *fExists = RTDirExists(pszDir); 938 return rc; 939 } 940 941 static int ctrlCopyDirExistsOnDest(PCOPYCONTEXT pContext, const char *pszDir, 942 bool *fExists) 943 { 944 return ctrlCopyDirExists(pContext, pContext->fHostToGuest, 945 pszDir, fExists); 946 } 947 948 static int ctrlCopyDirExistsOnSource(PCOPYCONTEXT pContext, const char *pszDir, 949 bool *fExists) 950 { 951 return ctrlCopyDirExists(pContext, !pContext->fHostToGuest, 952 pszDir, fExists); 953 } 954 955 static int ctrlCopyFileExists(PCOPYCONTEXT pContext, bool bOnGuest, 956 const char *pszFile, bool *fExists) 957 { 958 AssertPtrReturn(pContext, false); 959 AssertPtrReturn(pszFile, false); 960 AssertPtrReturn(fExists, false); 961 962 int rc = VINF_SUCCESS; 963 if (bOnGuest) 964 { 965 BOOL fFileExists = FALSE; 966 HRESULT hr = pContext->pGuest->FileExists(Bstr(pszFile).raw(), 967 Bstr(pContext->pszUsername).raw(), 968 Bstr(pContext->pszPassword).raw(), &fFileExists); 969 if (FAILED(hr)) 970 rc = ctrlPrintError(pContext->pGuest, COM_IIDOF(IGuest)); 971 else 972 *fExists = fFileExists ? true : false; 973 } 974 else 975 *fExists = RTFileExists(pszFile); 976 return rc; 977 } 978 979 static int ctrlCopyFileExistsOnDest(PCOPYCONTEXT pContext, const char *pszFile, 980 bool *fExists) 981 { 982 return ctrlCopyFileExists(pContext, pContext->fHostToGuest, 983 pszFile, fExists); 984 } 985 986 static int ctrlCopyFileExistsOnSource(PCOPYCONTEXT pContext, const char *pszFile, 987 bool *fExists) 988 { 989 return ctrlCopyFileExists(pContext, !pContext->fHostToGuest, 990 pszFile, fExists); 991 } 992 993 static int ctrlCopyFileToTarget(PCOPYCONTEXT pContext, const char *pszFileSource, 994 const char *pszFileDest, uint32_t fFlags) 995 { 996 AssertPtrReturn(pContext, VERR_INVALID_POINTER); 997 AssertPtrReturn(pszFileSource, VERR_INVALID_POINTER); 998 AssertPtrReturn(pszFileDest, VERR_INVALID_POINTER); 999 1000 if (pContext->fVerbose) 1001 { 1002 RTPrintf("Copying \"%s\" to \"%s\" ...\n", 1003 pszFileSource, pszFileDest); 1004 } 1005 1006 int vrc = VINF_SUCCESS; 1007 ComPtr<IProgress> progress; 1008 HRESULT hr; 1009 if (pContext->fHostToGuest) 1010 { 1011 hr = pContext->pGuest->CopyToGuest(Bstr(pszFileSource).raw(), Bstr(pszFileDest).raw(), 1012 Bstr(pContext->pszUsername).raw(), Bstr(pContext->pszPassword).raw(), 1013 fFlags, progress.asOutParam()); 1014 } 1015 else 1016 { 1017 hr = pContext->pGuest->CopyFromGuest(Bstr(pszFileSource).raw(), Bstr(pszFileDest).raw(), 1018 Bstr(pContext->pszUsername).raw(), Bstr(pContext->pszPassword).raw(), 1019 fFlags, progress.asOutParam()); 1020 } 1021 1022 if (FAILED(hr)) 1023 vrc = ctrlPrintError(pContext->pGuest, COM_IIDOF(IGuest)); 1024 else 1025 { 1026 hr = showProgress(progress); 1027 if (FAILED(hr)) 1028 vrc = ctrlPrintProgressError(progress); 1029 } 1030 1031 return vrc; 1032 } 1033 1034 static int ctrlCopyDirToGuest(PCOPYCONTEXT pContext, 1035 const char *pszSource, const char *pszFilter, 1036 const char *pszDest, uint32_t fFlags, 1037 const char *pszSubDir /* For recursion */) 1038 { 1039 AssertPtrReturn(pContext, VERR_INVALID_POINTER); 1040 AssertPtrReturn(pszSource, VERR_INVALID_POINTER); 1041 /* Filter is optional. */ 1042 AssertPtrReturn(pszDest, VERR_INVALID_POINTER); 800 1043 /* Sub directory is optional. */ 801 /* Filter directory is optional. */802 AssertPtrReturn(pszDest, VERR_INVALID_POINTER);803 AssertPtrReturn(pcObjects, VERR_INVALID_POINTER);804 1044 805 1045 /* … … 807 1047 */ 808 1048 char szCurDir[RTPATH_MAX]; 809 int rc = RTStrCopy(szCurDir, sizeof(szCurDir), psz RootDir);810 if (RT_SUCCESS(rc) && pszSubDir != NULL)1049 int rc = RTStrCopy(szCurDir, sizeof(szCurDir), pszSource); 1050 if (RT_SUCCESS(rc) && pszSubDir) 811 1051 rc = RTPathAppend(szCurDir, sizeof(szCurDir), pszSubDir); 812 1052 813 if (RT_SUCCESS(rc)) 814 { 815 ULONG uDirHandle; 816 HRESULT hr = pGuest->DirectoryOpen(Bstr(szCurDir).raw(), Bstr(pszFilter).raw(), fFlags, 817 Bstr(pszUsername).raw(), Bstr(pszPassword).raw(), &uDirHandle); 818 if (FAILED(hr)) 819 rc = ctrlPrintError(pGuest, COM_IIDOF(IGuest)); 820 else 821 { 822 ComPtr <IGuestDirEntry> dirEntry; 823 while (SUCCEEDED(hr = pGuest->DirectoryRead(uDirHandle, dirEntry.asOutParam()))) 824 { 825 GuestDirEntryType_T enmType; 826 dirEntry->COMGETTER(Type)(&enmType); 827 828 Bstr strName; 829 dirEntry->COMGETTER(Name)(strName.asOutParam()); 830 831 switch (enmType) 832 { 833 case GuestDirEntryType_Directory: 834 { 835 /* Skip "." and ".." entries. */ 836 if ( !strName.compare(Bstr(".")) 837 || !strName.compare(Bstr(".."))) 838 break; 839 840 const char *pszName = Utf8Str(strName).c_str(); 841 if (fFlags & CopyFileFlag_Recursive) 842 { 843 char *pszNewSub = NULL; 844 if (pszSubDir) 845 RTStrAPrintf(&pszNewSub, "%s/%s", pszSubDir, pszName); 846 else 847 RTStrAPrintf(&pszNewSub, "%s", pszName); 848 849 if (pszNewSub) 850 { 851 dirMap[pszNewSub]; 852 853 rc = ctrlCopyDirectoryReadGuest(pGuest, pszUsername, pszPassword, 854 pszRootDir, pszNewSub, 855 pszFilter, pszDest, 856 fFlags, pcObjects, dirMap); 857 RTStrFree(pszNewSub); 858 } 859 else 860 rc = VERR_NO_MEMORY; 861 } 862 break; 863 } 864 865 case GuestDirEntryType_Symlink: 866 if ( (fFlags & CopyFileFlag_Recursive) 867 && (fFlags & CopyFileFlag_FollowLinks)) 868 { 869 /* Fall through to next case is intentional. */ 870 } 871 else 872 break; 873 874 case GuestDirEntryType_File: 875 { 876 const char *pszName = Utf8Str(strName).c_str(); 877 if ( !pszFilter 878 || RTStrSimplePatternMatch(pszFilter, pszName)) 879 { 880 dirMap[pszSubDir].push_back(DESTFILEENTRY(pszName)); 881 *pcObjects += 1; 882 } 883 break; 884 } 885 886 default: 887 break; 888 } 889 } 890 891 hr = pGuest->DirectoryClose(uDirHandle); 892 if (FAILED(rc)) 893 rc = ctrlPrintError(pGuest, COM_IIDOF(IGuest)); 894 } 895 } 896 return rc; 897 } 898 899 /** 900 * Reads a specified directory (recursively) based on the copy flags 901 * and appends all matching entries to the supplied list. 902 * 903 * @return IPRT status code. 904 * @param pszRootDir Directory to start with. Must end with 905 * a trailing slash and must be absolute. 906 * @param pszSubDir Sub directory part relative to the root 907 * directory; needed for recursion. 908 * @param pszFilter Search filter (e.g. *.pdf). 909 * @param pszDest Destination directory. 910 * @param fFlags Copy flags. 911 * @param pcObjects Where to store the overall objects to 912 * copy found. 913 * @param dirMap Reference to destination directory map to store found 914 * directories (primary key) + files (secondary key, vector). 915 */ 916 static int ctrlCopyDirectoryReadHost(const char *pszRootDir, const char *pszSubDir, 917 const char *pszFilter, const char *pszDest, 918 uint32_t fFlags, uint32_t *pcObjects, DESTDIRMAP &dirMap) 919 { 920 AssertPtrReturn(pszRootDir, VERR_INVALID_POINTER); 921 /* Sub directory is optional. */ 922 /* Filter directory is optional. */ 923 AssertPtrReturn(pszDest, VERR_INVALID_POINTER); 924 AssertPtrReturn(pcObjects, VERR_INVALID_POINTER); 925 926 /* 927 * Construct current path. 928 */ 929 char szCurDir[RTPATH_MAX]; 930 int rc = RTStrCopy(szCurDir, sizeof(szCurDir), pszRootDir); 931 if (RT_SUCCESS(rc) && pszSubDir != NULL) 932 rc = RTPathAppend(szCurDir, sizeof(szCurDir), pszSubDir); 1053 /* Flag indicating whether the current directory was created on the 1054 * target or not. */ 1055 bool fDirCreated = false; 933 1056 934 1057 /* … … 977 1100 if (pszNewSub) 978 1101 { 979 dirMap[pszNewSub]; 980 981 rc = ctrlCopyDirectoryReadHost(pszRootDir, pszNewSub, 982 pszFilter, pszDest, 983 fFlags, pcObjects, dirMap); 1102 rc = ctrlCopyDirToGuest(pContext, 1103 pszSource, pszFilter, 1104 pszDest, fFlags, pszNewSub); 984 1105 RTStrFree(pszNewSub); 985 1106 } … … 1004 1125 || RTStrSimplePatternMatch(pszFilter, DirEntry.szName)) 1005 1126 { 1006 dirMap[pszSubDir].push_back(DESTFILEENTRY(Utf8Str(DirEntry.szName))); 1007 *pcObjects += 1; 1127 if (!fDirCreated) 1128 { 1129 char *pszDestDir; 1130 rc = ctrlCopyTranslatePath(pContext, pszSource, szCurDir, 1131 pszDest, &pszDestDir); 1132 if (RT_SUCCESS(rc)) 1133 { 1134 rc = ctrlCopyDirCreate(pContext, pszDestDir); 1135 RTStrFree(pszDestDir); 1136 1137 fDirCreated = true; 1138 } 1139 } 1140 1141 if (RT_SUCCESS(rc)) 1142 { 1143 char *pszFileSource; 1144 if (RTStrAPrintf(&pszFileSource, "%s/%s", 1145 szCurDir, DirEntry.szName)) 1146 { 1147 char *pszFileDest; 1148 rc = ctrlCopyTranslatePath(pContext, pszSource, pszFileSource, 1149 pszDest, &pszFileDest); 1150 if (RT_SUCCESS(rc)) 1151 { 1152 rc = ctrlCopyFileToTarget(pContext, pszFileSource, 1153 pszFileDest, 0 /* Flags? */); 1154 RTStrFree(pszFileDest); 1155 } 1156 RTStrFree(pszFileSource); 1157 } 1158 } 1008 1159 } 1009 1160 break; … … 1022 1173 } 1023 1174 1024 /** 1025 * Constructs a destinations map from a source entry and a destination root. 1026 * 1027 * @return IPRT status code. 1028 * @param fHostToGuest 1029 * @param sourceEntry Reference to a specified source entry to use. 1030 * @param fFlags Copy file flags. Needed for recursive directory parsing. 1031 * @param pszDestRoot Pointer to destination root. This can be used to add one or 1032 * more directories to the actual destination path. 1033 * @param mapDest Reference to the destination map for storing the actual result. 1034 * @param pcObjects Pointer to a total object (file) count to copy. 1035 */ 1036 static int ctrlCopyConstructDestinationsForGuest(SOURCEFILEENTRY &sourceEntry, uint32_t fFlags, 1037 const char *pszDestRoot, DESTDIRMAP &mapDest, 1038 uint32_t *pcObjects) 1039 { 1040 int rc = VINF_SUCCESS; 1041 const char *pszSource = sourceEntry.mSource.c_str(); 1042 1043 if ( RTPathFilename(pszSource) 1044 && RTFileExists(pszSource)) 1045 { 1046 /* Source is a single file. */ 1047 char *pszFileName = RTPathFilename(pszSource); 1048 mapDest[Utf8Str("")].push_back(DESTFILEENTRY(pszFileName)); 1049 1050 *pcObjects += 1; 1051 } 1175 static int ctrlCopyDirToHost(PCOPYCONTEXT pContext, 1176 const char *pszSource, const char *pszFilter, 1177 const char *pszDest, uint32_t fFlags, 1178 const char *pszSubDir /* For recursion */) 1179 { 1180 AssertPtrReturn(pContext, VERR_INVALID_POINTER); 1181 AssertPtrReturn(pszSource, VERR_INVALID_POINTER); 1182 /* Filter is optional. */ 1183 AssertPtrReturn(pszDest, VERR_INVALID_POINTER); 1184 /* Sub directory is optional. */ 1185 1186 /* 1187 * Construct current path. 1188 */ 1189 char szCurDir[RTPATH_MAX]; 1190 int rc = RTStrCopy(szCurDir, sizeof(szCurDir), pszSource); 1191 if (RT_SUCCESS(rc) && pszSubDir) 1192 rc = RTPathAppend(szCurDir, sizeof(szCurDir), pszSubDir); 1193 1194 /* Flag indicating whether the current directory was created on the 1195 * target or not. */ 1196 bool fDirCreated = false; 1197 1198 ULONG uDirHandle; 1199 HRESULT hr = pContext->pGuest->DirectoryOpen(Bstr(szCurDir).raw(), Bstr(pszFilter).raw(), 1200 fFlags, 1201 Bstr(pContext->pszUsername).raw(), Bstr(pContext->pszPassword).raw(), 1202 &uDirHandle); 1203 if (FAILED(hr)) 1204 rc = ctrlPrintError(pContext->pGuest, COM_IIDOF(IGuest)); 1052 1205 else 1053 1206 { 1054 /* Source is either a directory or a filter (e.g. *.dll). */ 1055 rc = ctrlCopyDirectoryReadHost(pszSource, 1056 NULL /* pszSubDir */, 1057 sourceEntry.mFilter.isEmpty() ? NULL : sourceEntry.mFilter.c_str(), 1058 pszDestRoot, fFlags, pcObjects, mapDest); 1059 } 1207 ComPtr <IGuestDirEntry> dirEntry; 1208 while (SUCCEEDED(hr = pContext->pGuest->DirectoryRead(uDirHandle, dirEntry.asOutParam()))) 1209 { 1210 GuestDirEntryType_T enmType; 1211 dirEntry->COMGETTER(Type)(&enmType); 1212 1213 Bstr strName; 1214 dirEntry->COMGETTER(Name)(strName.asOutParam()); 1215 1216 switch (enmType) 1217 { 1218 case GuestDirEntryType_Directory: 1219 { 1220 /* Skip "." and ".." entries. */ 1221 if ( !strName.compare(Bstr(".")) 1222 || !strName.compare(Bstr(".."))) 1223 break; 1224 1225 if (fFlags & CopyFileFlag_Recursive) 1226 { 1227 Utf8Str strDir(strName); 1228 char *pszNewSub = NULL; 1229 if (pszSubDir) 1230 RTStrAPrintf(&pszNewSub, "%s/%s", pszSubDir, strDir.c_str()); 1231 else 1232 RTStrAPrintf(&pszNewSub, "%s", strDir.c_str()); 1233 1234 if (pszNewSub) 1235 { 1236 rc = ctrlCopyDirToHost(pContext, 1237 pszSource, pszFilter, 1238 pszDest, fFlags, pszNewSub); 1239 RTStrFree(pszNewSub); 1240 } 1241 else 1242 rc = VERR_NO_MEMORY; 1243 } 1244 break; 1245 } 1246 1247 case GuestDirEntryType_Symlink: 1248 if ( (fFlags & CopyFileFlag_Recursive) 1249 && (fFlags & CopyFileFlag_FollowLinks)) 1250 { 1251 /* Fall through to next case is intentional. */ 1252 } 1253 else 1254 break; 1255 1256 case GuestDirEntryType_File: 1257 { 1258 const char *pszName = Utf8Str(strName).c_str(); 1259 if ( !pszFilter 1260 || RTStrSimplePatternMatch(pszFilter, pszName)) 1261 { 1262 if (!fDirCreated) 1263 { 1264 char *pszDestDir; 1265 rc = ctrlCopyTranslatePath(pContext, pszSource, szCurDir, 1266 pszDest, &pszDestDir); 1267 if (RT_SUCCESS(rc)) 1268 { 1269 rc = ctrlCopyDirCreate(pContext, pszDestDir); 1270 RTStrFree(pszDestDir); 1271 1272 fDirCreated = true; 1273 } 1274 } 1275 1276 if (RT_SUCCESS(rc)) 1277 { 1278 Utf8Str strDir(strName); 1279 char *pszFileSource; 1280 if (RTStrAPrintf(&pszFileSource, "%s/%s", 1281 szCurDir, strDir.c_str())) 1282 { 1283 char *pszFileDest; 1284 rc = ctrlCopyTranslatePath(pContext, pszSource, pszFileSource, 1285 pszDest, &pszFileDest); 1286 if (RT_SUCCESS(rc)) 1287 { 1288 rc = ctrlCopyFileToTarget(pContext, pszFileSource, 1289 pszFileDest, 0 /* Flags? */); 1290 RTStrFree(pszFileDest); 1291 } 1292 RTStrFree(pszFileSource); 1293 } 1294 } 1295 } 1296 break; 1297 } 1298 1299 default: 1300 break; 1301 } 1302 } 1303 1304 hr = pContext->pGuest->DirectoryClose(uDirHandle); 1305 if (FAILED(rc)) 1306 rc = ctrlPrintError(pContext->pGuest, COM_IIDOF(IGuest)); 1307 } 1308 1060 1309 return rc; 1061 1310 } 1062 1311 1063 static int ctrlCopyConstructDestinationsForHost(IGuest *pGuest, 1064 const char *pszUsername, const char *pszPassword, 1065 SOURCEFILEENTRY &sourceEntry, uint32_t fFlags, 1066 const char *pszDestRoot, DESTDIRMAP &mapDest, 1067 uint32_t *pcObjects) 1068 { 1069 int rc = VINF_SUCCESS; 1070 const char *pszSource = sourceEntry.mSource.c_str(); 1071 1072 BOOL fExists = FALSE; 1073 HRESULT hr = pGuest->FileExists(Bstr(pszSource).raw(), 1074 Bstr(pszUsername).raw(), Bstr(pszPassword).raw(), &fExists); 1075 if (FAILED(rc)) 1076 rc = ctrlPrintError(pGuest, COM_IIDOF(IGuest)); 1312 static int ctrlCopyDirToTarget(PCOPYCONTEXT pContext, 1313 const char *pszSource, const char *pszFilter, 1314 const char *pszDest, uint32_t fFlags, 1315 const char *pszSubDir /* For recursion */) 1316 { 1317 if (pContext->fHostToGuest) 1318 return ctrlCopyDirToGuest(pContext, pszSource, pszFilter, 1319 pszDest, fFlags, pszSubDir); 1320 return ctrlCopyDirToHost(pContext, pszSource, pszFilter, 1321 pszDest, fFlags, pszSubDir); 1322 } 1323 1324 static int ctrlCopyCreateSourceRoot(const char *pszSource, char **ppszSourceRoot) 1325 { 1326 AssertPtrReturn(pszSource, VERR_INVALID_POINTER); 1327 AssertPtrReturn(ppszSourceRoot, VERR_INVALID_POINTER); 1328 1329 char *pszNewRoot = RTStrDup(pszSource); 1330 AssertPtrReturn(pszNewRoot, VERR_NO_MEMORY); 1331 1332 size_t lenRoot = strlen(pszNewRoot); 1333 if ( lenRoot 1334 && pszNewRoot[lenRoot - 1] == '/' 1335 && pszNewRoot[lenRoot - 1] == '\\' 1336 && lenRoot > 1 1337 && pszNewRoot[lenRoot - 2] == '/' 1338 && pszNewRoot[lenRoot - 2] == '\\') 1339 { 1340 *ppszSourceRoot = pszNewRoot; 1341 if (lenRoot > 1) 1342 *ppszSourceRoot[lenRoot - 2] = '\0'; 1343 *ppszSourceRoot[lenRoot - 1] = '\0'; 1344 } 1077 1345 else 1078 1346 { 1079 if (fExists) 1080 { 1081 /* Source is a single file. */ 1082 char *pszFileName = RTPathFilename(pszSource); 1083 mapDest[Utf8Str(pszDestRoot)].push_back(DESTFILEENTRY(pszFileName)); 1084 1085 *pcObjects++; 1086 } 1087 else 1088 { 1089 /* Source is either a directory or a filter (e.g. *.dll). */ 1090 rc = ctrlCopyDirectoryReadGuest(pGuest, pszUsername, pszPassword, 1091 pszSource, NULL /* pszSubDir */, 1092 sourceEntry.mFilter.isEmpty() ? NULL : sourceEntry.mFilter.c_str(), 1093 pszDestRoot, fFlags, pcObjects, mapDest); 1094 } 1095 } 1096 return rc; 1097 } 1098 1099 /** 1100 * Prepares the destination directory hirarchy on the guest side by creating the directories 1101 * and sets the appropriate access rights. 1102 * 1103 * @return IPRT status code. 1104 * @param pGuest IGuest interface pointer. 1105 * @param fHostToGuest 1106 * @param itDest Destination map iterator to process. 1107 * @param pszDestRoot Destination root to use. 1108 * @param pszUsername Username to use. 1109 * @param pszPassword Password to use. 1110 */ 1111 static int ctrlCopyPrepareDestDirectory(IGuest *pGuest, bool fHostToGuest, 1112 const char *pszDestRoot, const char *pszDestSub, 1113 const char *pszUsername, const char *pszPassword) 1114 { 1115 AssertPtrReturn(pGuest, VERR_INVALID_POINTER); 1116 AssertPtrReturn(pszDestRoot, VERR_INVALID_POINTER); 1117 AssertPtrReturn(pszDestSub, VERR_INVALID_POINTER); 1118 AssertPtrReturn(pszUsername, VERR_INVALID_POINTER); 1119 AssertPtrReturn(pszPassword, VERR_INVALID_POINTER); 1120 1121 char *pszDestFinal = NULL; 1122 int rc = VINF_SUCCESS; 1123 1124 /* Create root directory (= empty name) and skip the rest for 1125 * this round. */ 1126 if (!strlen(pszDestSub)) 1127 { 1128 pszDestFinal = RTStrDup(pszDestRoot); 1129 if (!pszDestFinal) 1130 rc = VERR_NO_MEMORY; 1131 } 1132 else /* Create sub-directories, also empty ones. */ 1133 { 1134 if (!RTStrAPrintf(&pszDestFinal, "%s/%s", pszDestRoot, pszDestSub)) 1135 rc = VERR_NO_MEMORY; 1136 } 1137 1138 if (RT_SUCCESS(rc) && pszDestFinal) 1139 { 1140 if (fHostToGuest) /* We want to create directories on the guest. */ 1141 { 1142 HRESULT hrc = pGuest->DirectoryCreate(Bstr(pszDestFinal).raw(), 1143 Bstr(pszUsername).raw(), Bstr(pszPassword).raw(), 1144 700, DirectoryCreateFlag_Parents); 1145 if (FAILED(hrc)) 1146 rc = ctrlPrintError(pGuest, COM_IIDOF(IGuest)); 1147 } 1148 else /* ... or on the host. */ 1149 { 1150 rc = RTDirCreate(pszDestFinal, 700); 1151 } 1152 RTStrFree(pszDestFinal); 1153 } 1154 return rc; 1155 } 1156 1157 /** 1158 * Copys a file from host to the guest. 1159 * 1160 * @return IPRT status code. 1161 * @param pGuest IGuest interface pointer. 1162 * @param pszSource Source path of existing host file to copy to the guest. 1163 * @param pszDest Destination path on guest to copy the file to. 1164 * @param pszUserName User name on guest to use for the copy operation. 1165 * @param pszPassword Password of user account. 1166 * @param fFlags Copy flags. 1167 */ 1168 static int ctrlCopyFileToGuest(IGuest *pGuest, const char *pszSource, const char *pszDest, 1169 const char *pszUserName, const char *pszPassword, 1170 uint32_t fFlags) 1171 { 1172 AssertPtrReturn(pGuest, VERR_INVALID_POINTER); 1173 AssertPtrReturn(pszSource, VERR_INVALID_POINTER); 1174 AssertPtrReturn(pszDest, VERR_INVALID_POINTER); 1175 AssertPtrReturn(pszUserName, VERR_INVALID_POINTER); 1176 AssertPtrReturn(pszPassword, VERR_INVALID_POINTER); 1177 1178 int vrc = VINF_SUCCESS; 1179 ComPtr<IProgress> progress; 1180 HRESULT rc = pGuest->CopyToGuest(Bstr(pszSource).raw(), Bstr(pszDest).raw(), 1181 Bstr(pszUserName).raw(), Bstr(pszPassword).raw(), 1182 fFlags, progress.asOutParam()); 1183 if (FAILED(rc)) 1184 vrc = ctrlPrintError(pGuest, COM_IIDOF(IGuest)); 1185 else 1186 { 1187 rc = showProgress(progress); 1188 if (FAILED(rc)) 1189 vrc = ctrlPrintProgressError(progress); 1190 } 1191 return vrc; 1192 } 1193 1194 /** 1195 * Copys a file from guest to the host. 1196 * 1197 * @return IPRT status code. 1198 * @param pGuest IGuest interface pointer. 1199 * @param pszSource Source path of existing guest file to copy to the host. 1200 * @param pszDest Destination path/file on host to copy the file to. 1201 * @param pszUserName User name on guest to use for the copy operation. 1202 * @param pszPassword Password of user account. 1203 * @param fFlags Copy flags. 1204 */ 1205 static int ctrlCopyFileToHost(IGuest *pGuest, const char *pszSource, const char *pszDest, 1206 const char *pszUserName, const char *pszPassword, 1207 uint32_t fFlags) 1208 { 1209 AssertPtrReturn(pGuest, VERR_INVALID_POINTER); 1210 AssertPtrReturn(pszSource, VERR_INVALID_POINTER); 1211 AssertPtrReturn(pszDest, VERR_INVALID_POINTER); 1212 AssertPtrReturn(pszUserName, VERR_INVALID_POINTER); 1213 AssertPtrReturn(pszPassword, VERR_INVALID_POINTER); 1214 1215 int vrc = VINF_SUCCESS; 1216 ComPtr<IProgress> progress; 1217 HRESULT rc = pGuest->CopyFromGuest(Bstr(pszSource).raw(), Bstr(pszDest).raw(), 1218 Bstr(pszUserName).raw(), Bstr(pszPassword).raw(), 1219 fFlags, progress.asOutParam()); 1220 if (FAILED(rc)) 1221 vrc = ctrlPrintError(pGuest, COM_IIDOF(IGuest)); 1222 else 1223 { 1224 rc = showProgress(progress); 1225 if (FAILED(rc)) 1226 vrc = ctrlPrintProgressError(progress); 1227 } 1228 return vrc; 1229 } 1230 1231 static int ctrlCopyToDestDirectory(IGuest *pGuest, bool fVerbose, bool fDryRun, bool fHostToGuest, 1232 const char *pszSourceDir, 1233 const char *pszDestRoot, const char *pszDestSub, const char *pszFileName, 1234 uint32_t uFlags, const char *pszUsername, const char *pszPassword) 1235 { 1236 AssertPtrReturn(pGuest, VERR_INVALID_POINTER); 1237 AssertPtrReturn(pszDestRoot, VERR_INVALID_POINTER); 1238 AssertPtrReturn(pszDestSub, VERR_INVALID_POINTER); 1239 AssertPtrReturn(pszFileName, VERR_INVALID_POINTER); 1240 AssertPtrReturn(pszSourceDir, VERR_INVALID_POINTER); 1241 AssertPtrReturn(pszUsername, VERR_INVALID_POINTER); 1242 AssertPtrReturn(pszPassword, VERR_INVALID_POINTER); 1243 1244 int iLen; 1245 char *pszSource; 1246 if (!strlen(pszDestSub)) 1247 iLen = RTStrAPrintf(&pszSource, "%s/%s", pszSourceDir, pszFileName); 1248 else 1249 iLen = RTStrAPrintf(&pszSource, "%s/%s/%s", 1250 pszSourceDir, pszDestSub, pszFileName); 1251 if (!iLen) 1252 return VERR_NO_MEMORY; 1253 1254 char *pszDest; 1255 if (!strlen(pszDestSub)) 1256 iLen = RTStrAPrintf(&pszDest, "%s/%s", pszDestRoot, pszFileName); 1257 else 1258 iLen = RTStrAPrintf(&pszDest, "%s/%s/%s", pszDestRoot, pszDestSub, 1259 pszFileName); 1260 if (!iLen) 1261 { 1262 RTStrFree(pszSource); 1263 return VERR_NO_MEMORY; 1264 } 1265 1266 if (fVerbose) 1267 RTPrintf("\"%s\" -> \"%s\"\n", pszSource, pszDest); 1268 1269 int rc = VINF_SUCCESS; 1270 1271 /* Finally copy the desired file (if no dry run selected). */ 1272 if (!fDryRun) 1273 { 1274 if (fHostToGuest) 1275 rc = ctrlCopyFileToGuest(pGuest, pszSource, pszDest, 1276 pszUsername, pszPassword, uFlags); 1277 else 1278 rc = ctrlCopyFileToHost(pGuest, pszSource, pszDest, 1279 pszUsername, pszPassword, uFlags); 1280 } 1281 RTStrFree(pszSource); 1282 RTStrFree(pszDest); 1283 1284 return rc; 1347 /* If there's anything (like a file name or a filter), 1348 * strip it! */ 1349 RTPathStripFilename(pszNewRoot); 1350 *ppszSourceRoot = pszNewRoot; 1351 } 1352 1353 return VINF_SUCCESS; 1354 } 1355 1356 static void ctrlCopyFreeSourceRoot(char *pszSourceRoot) 1357 { 1358 RTStrFree(pszSourceRoot); 1285 1359 } 1286 1360 … … 1415 1489 } 1416 1490 1417 /* Strip traling slash from destination path. */ 1418 RTPathStripTrailingSlash(Utf8Dest.mutableRaw()); 1419 Utf8Dest.jolt(); 1420 1421 /* 1422 * Here starts the actual fun! 1423 */ 1424 for (unsigned long s = 0; s < vecSources.size(); s++) 1425 { 1426 char *pszSourceDir; 1427 if (RTDirExists(vecSources[s].mSource.c_str())) 1428 pszSourceDir = RTStrDup(vecSources[s].mSource.c_str()); 1429 else 1430 { 1431 pszSourceDir = RTStrDup(vecSources[s].mSource.c_str()); 1432 RTPathStripFilename(pszSourceDir); 1433 } 1434 1435 uint32_t cObjects = 0; 1436 DESTDIRMAP mapDest; 1437 const char *pszDestRoot = Utf8Dest.c_str(); 1438 1439 if (fHostToGuest) 1440 vrc = ctrlCopyConstructDestinationsForGuest(vecSources[s], fFlags, pszDestRoot, 1441 mapDest, &cObjects); 1442 else 1443 vrc = ctrlCopyConstructDestinationsForHost(guest, Utf8UserName.c_str(), Utf8Password.c_str(), 1444 vecSources[s], fFlags, pszDestRoot, 1445 mapDest, &cObjects); 1446 if (RT_FAILURE(vrc)) 1447 { 1448 if ( fVerbose 1449 && vrc == VERR_FILE_NOT_FOUND) 1450 { 1451 RTPrintf("Warning: Source \"%s\" does not exist, skipping!\n", 1452 vecSources[s].mSource.c_str()); 1453 } 1454 } 1455 else 1456 { 1457 /* 1458 * Prepare directory structure of each destination directory. 1459 */ 1460 DESTDIRMAPITER itDest; 1461 for (itDest = mapDest.begin(); itDest != mapDest.end(); itDest++) 1462 { 1463 if (fVerbose) 1491 /* Create the copy context -- it contains all information 1492 * the routines need to know when handling the actual copying. */ 1493 PCOPYCONTEXT pContext; 1494 vrc = ctrlCopyContextCreate(guest, fVerbose, fHostToGuest, 1495 Utf8UserName.c_str(), Utf8Password.c_str(), 1496 &pContext); 1497 if (RT_FAILURE(vrc)) 1498 { 1499 RTMsgError("Unable to create copy context, rc=%Rrc\n", vrc); 1500 return RTEXITCODE_FAILURE; 1501 } 1502 1503 /* If the destination is a path, (try to) create it. */ 1504 const char *pszDest = Utf8Dest.c_str(); 1505 AssertPtr(pszDest); 1506 size_t lenDest = strlen(pszDest); 1507 if ( lenDest 1508 ||pszDest[lenDest - 1] == '/' 1509 || pszDest[lenDest - 1] == '\\') 1510 { 1511 vrc = ctrlCopyDirCreate(pContext, pszDest); 1512 } 1513 1514 if (RT_SUCCESS(vrc)) 1515 { 1516 /* 1517 * Here starts the actual fun! 1518 * Handle all given sources one by one. 1519 */ 1520 for (unsigned long s = 0; s < vecSources.size(); s++) 1521 { 1522 const char *pszSource = vecSources[s].mSource.c_str(); 1523 const char *pszFilter = vecSources[s].mFilter.c_str(); 1524 1525 char *pszSourceRoot; 1526 vrc = ctrlCopyCreateSourceRoot(pszSource, &pszSourceRoot); 1527 if (RT_FAILURE(vrc)) 1528 { 1529 RTMsgError("Unable to create source root, rc=%Rrc\n", vrc); 1530 break; 1531 } 1532 1533 if (fVerbose) 1534 RTPrintf("Source: %s\n", pszSource); 1535 1536 /* @todo Files with filter?? */ 1537 bool fExists; 1538 vrc = ctrlCopyFileExistsOnSource(pContext, pszSource, &fExists); 1539 if (RT_SUCCESS(vrc)) 1540 { 1541 if (fExists) 1464 1542 { 1465 const char *pszSubDir = itDest->first.c_str(); 1466 AssertPtr(pszSubDir); 1467 if (!strlen(pszSubDir)) 1468 RTPrintf("Preparing directory \"%s\" ...\n", pszDestRoot); 1543 /* Single file. */ 1544 char *pszDest; 1545 vrc = ctrlCopyTranslatePath(pContext, pszSourceRoot, pszSource, 1546 Utf8Dest.c_str(), &pszDest); 1547 if (RT_SUCCESS(vrc)) 1548 { 1549 vrc = ctrlCopyFileToTarget(pContext, pszSource, 1550 pszDest, fFlags); 1551 RTStrFree(pszDest); 1552 } 1469 1553 else 1470 RTPrintf("Preparing directory \"%s/%s\" ...\n", pszDestRoot, 1471 itDest->first.c_str()); 1554 { 1555 RTMsgError("Unable to translate path for \"%s\", rc=%Rrc\n", 1556 pszSource, vrc); 1557 } 1472 1558 } 1473 if (!fDryRun) 1474 vrc = ctrlCopyPrepareDestDirectory(guest, fHostToGuest, 1475 pszDestRoot, itDest->first.c_str(), 1476 Utf8UserName.c_str(), Utf8Password.c_str()); 1477 if (RT_FAILURE(vrc)) 1478 break; 1559 else 1560 { 1561 if ( (RT_SUCCESS(ctrlCopyDirExistsOnSource(pContext, pszSource, &fExists)) 1562 && fExists) 1563 || ( RT_SUCCESS(ctrlCopyDirExistsOnSource(pContext, pszSourceRoot, &fExists)) 1564 && fExists 1565 && pszFilter) 1566 ) 1567 { 1568 /* Directory (with filter?). */ 1569 vrc = ctrlCopyDirToTarget(pContext, pszSource, pszFilter, 1570 Utf8Dest.c_str(), fFlags, NULL /* Subdir */); 1571 } 1572 } 1573 } 1574 1575 ctrlCopyFreeSourceRoot(pszSourceRoot); 1576 1577 if ( RT_SUCCESS(vrc) 1578 && !fExists) 1579 { 1580 RTMsgError("Warning: Source \"%s\" does not exist, skipping!\n", 1581 pszSource); 1582 continue; 1479 1583 } 1480 1584 1481 1585 if (RT_FAILURE(vrc)) 1482 break; 1483 1484 if (fVerbose) 1485 { 1486 if (!cObjects) 1487 RTPrintf("Warning: Source \"%s\" has no (matching) files to copy, skipping!\n", 1488 vecSources[s].mSource.c_str()); 1489 else 1490 RTPrintf("Copying \"%s\" (%u files) ...\n", 1491 vecSources[s].mSource.c_str(), cObjects); 1492 } 1493 1494 /* 1495 * Copy files of each destination root directory to the guest. 1496 */ 1497 for (itDest = mapDest.begin(); itDest != mapDest.end(); itDest++) 1498 { 1499 if (fVerbose && itDest->second.size()) 1500 { 1501 if (itDest->first.isEmpty()) 1502 RTPrintf("Copying %u files ...\n", itDest->second.size()); 1503 else 1504 RTPrintf("Copying directory \"%s\" (%u files) ...\n", 1505 itDest->first.c_str(), itDest->second.size()); 1506 } 1507 1508 for (unsigned long l = 0; l < itDest->second.size(); l++) 1509 { 1510 vrc = ctrlCopyToDestDirectory(guest, fVerbose, fDryRun, fHostToGuest, 1511 pszSourceDir, 1512 pszDestRoot, itDest->first.c_str() /* Sub directory */, 1513 itDest->second[l].mFileName.c_str() /* Filename */, 1514 fFlags, Utf8UserName.c_str(), Utf8Password.c_str()); 1515 if (RT_FAILURE(vrc)) 1516 break; 1517 } 1518 1519 if (RT_FAILURE(vrc)) 1520 break; 1521 } 1522 1523 if (RT_FAILURE(vrc)) 1524 break; 1525 } 1526 1527 RTStrFree(pszSourceDir); 1528 } 1586 { 1587 RTMsgError("Error processing \"%s\", rc=%Rrc\n", 1588 pszSource, vrc); 1589 break; 1590 } 1591 } 1592 } 1593 1594 ctrlCopyContextFree(pContext); 1529 1595 1530 1596 return RT_SUCCESS(vrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; … … 1632 1698 ctrlPrintError(guest, COM_IIDOF(IGuest)); /* Return code ignored, save original rc. */ 1633 1699 break; 1700 } 1701 1702 it++; 1703 } 1704 1705 if (FAILED(hrc)) 1706 rcExit = RTEXITCODE_FAILURE; 1707 } 1708 1709 return rcExit; 1710 } 1711 1712 static int handleCtrlStat(ComPtr<IGuest> guest, HandlerArg *pArg) 1713 { 1714 AssertPtrReturn(pArg, VERR_INVALID_PARAMETER); 1715 1716 /* 1717 * Parse arguments. 1718 * 1719 * Note! No direct returns here, everyone must go thru the cleanup at the 1720 * end of this function. 1721 */ 1722 static const RTGETOPTDEF s_aOptions[] = 1723 { 1724 /** @todo Implement "--dereference/-L", and "--file-system/-f" later! */ 1725 { "--password", 'p', RTGETOPT_REQ_STRING }, 1726 { "--username", 'u', RTGETOPT_REQ_STRING }, 1727 { "--verbose", 'v', RTGETOPT_REQ_NOTHING } 1728 }; 1729 1730 int ch; 1731 RTGETOPTUNION ValueUnion; 1732 RTGETOPTSTATE GetState; 1733 RTGetOptInit(&GetState, pArg->argc, pArg->argv, 1734 s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_OPTS_FIRST); 1735 1736 Utf8Str Utf8UserName; 1737 Utf8Str Utf8Password; 1738 1739 bool fVerbose = false; 1740 DESTDIRMAP mapDirs; 1741 1742 RTEXITCODE rcExit = RTEXITCODE_SUCCESS; 1743 while ( (ch = RTGetOpt(&GetState, &ValueUnion)) 1744 && rcExit == RTEXITCODE_SUCCESS) 1745 { 1746 /* For options that require an argument, ValueUnion has received the value. */ 1747 switch (ch) 1748 { 1749 case 'p': /* Password */ 1750 Utf8Password = ValueUnion.psz; 1751 break; 1752 1753 case 'u': /* User name */ 1754 Utf8UserName = ValueUnion.psz; 1755 break; 1756 1757 case 'v': /* Verbose */ 1758 fVerbose = true; 1759 break; 1760 1761 case VINF_GETOPT_NOT_OPTION: 1762 { 1763 mapDirs[ValueUnion.psz]; /* Add element to check to map. */ 1764 break; 1765 } 1766 1767 default: 1768 rcExit = RTGetOptPrintError(ch, &ValueUnion); 1769 break; 1770 } 1771 } 1772 1773 uint32_t cDirs = mapDirs.size(); 1774 if (rcExit == RTEXITCODE_SUCCESS && !cDirs) 1775 rcExit = errorSyntax(USAGE_GUESTCONTROL, "No element to check specified!"); 1776 1777 if (rcExit == RTEXITCODE_SUCCESS && Utf8UserName.isEmpty()) 1778 rcExit = errorSyntax(USAGE_GUESTCONTROL, "No user name specified!"); 1779 1780 if (rcExit == RTEXITCODE_SUCCESS) 1781 { 1782 /* 1783 * Create the directories. 1784 */ 1785 HRESULT hrc = S_OK; 1786 1787 DESTDIRMAPITER it = mapDirs.begin(); 1788 while (it != mapDirs.end()) 1789 { 1790 if (fVerbose) 1791 RTPrintf("Checking for element \"%s\" ...\n", it->first.c_str()); 1792 1793 BOOL fExists; 1794 hrc = guest->FileExists(Bstr(it->first).raw(), 1795 Bstr(Utf8UserName).raw(), Bstr(Utf8Password).raw(), 1796 &fExists); 1797 if (FAILED(hrc)) 1798 { 1799 ctrlPrintError(guest, COM_IIDOF(IGuest)); /* Return code ignored, save original rc. */ 1800 break; 1801 } 1802 else 1803 { 1804 /** @todo: Output vbox_stat's stdout output to get more information about 1805 * what happened. */ 1806 1807 /* If there's at least one element which does not exist on the guest, 1808 * drop out with exitcode 1. */ 1809 if (!fExists) 1810 { 1811 RTPrintf("Cannot stat for element \"%s\": No such file or directory.\n", 1812 it->first.c_str()); 1813 rcExit = RTEXITCODE_FAILURE; 1814 } 1634 1815 } 1635 1816 … … 1772 1953 rcExit = handleCtrlExecProgram(guest, &arg); 1773 1954 } 1774 #if 01775 1955 else if (!strcmp(pArg->argv[1], "copyfrom")) 1776 1956 { … … 1778 1958 false /* Guest to host */); 1779 1959 } 1780 #endif1781 1960 else if ( !strcmp(pArg->argv[1], "copyto") 1782 1961 || !strcmp(pArg->argv[1], "cp")) … … 1792 1971 rcExit = handleCtrlCreateDirectory(guest, &arg); 1793 1972 } 1973 else if ( !strcmp(pArg->argv[1], "stat")) 1974 { 1975 rcExit = handleCtrlStat(guest, &arg); 1976 } 1794 1977 else if ( !strcmp(pArg->argv[1], "updateadditions") 1795 1978 || !strcmp(pArg->argv[1], "updateadds")) -
trunk/src/VBox/Main/Makefile.kmk
r38082 r38085 649 649 src-client/DisplayImpl.cpp \ 650 650 src-client/GuestCtrlImpl.cpp \ 651 src-client/GuestCtrlIO.cpp \ 651 652 src-client/GuestImpl.cpp \ 652 653 src-client/KeyboardImpl.cpp \ -
trunk/src/VBox/Main/include/GuestImpl.h
r37863 r38085 115 115 116 116 // Public methods that are not in IDL (only called internally). 117 HRESULT directoryCreateInternal(IN_BSTR aDirectory, IN_BSTR aUserName, IN_BSTR aPassword, 118 ULONG aMode, ULONG aFlags, int *pRC); 119 HRESULT directoryOpenInternal(IN_BSTR aDirectory, IN_BSTR aFilter, 120 ULONG aFlags, 121 IN_BSTR aUserName, IN_BSTR aPassword, 122 ULONG *aHandle, int *pRC); 117 123 HRESULT executeProcessInternal(IN_BSTR aCommand, ULONG aFlags, 118 124 ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment), 119 125 IN_BSTR aUserName, IN_BSTR aPassword, 120 126 ULONG aTimeoutMS, ULONG *aPID, IProgress **aProgress, int *pRC); 121 HRESULT directoryCreateInternal(IN_BSTR aDirectory, IN_BSTR aUserName, IN_BSTR aPassword,122 ULONG aMode, ULONG aFlags, int *pRC);127 HRESULT fileExistsInternal(IN_BSTR aFile, IN_BSTR aUserName, IN_BSTR aPassword, BOOL *aExists, int *pRC); 128 HRESULT fileQuerySizeInternal(IN_BSTR aFile, IN_BSTR aUserName, IN_BSTR aPassword, LONG64 *aSize, int *pRC); 123 129 void setAdditionsInfo(Bstr aInterfaceVersion, VBOXOSTYPE aOsType); 124 130 void setAdditionsInfo2(Bstr aAdditionsVersion, Bstr aVersionName, Bstr aRevision); … … 196 202 int processSetStatus(uint32_t u32PID, ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags); 197 203 204 // Internal guest directory representation. 205 typedef struct VBOXGUESTCTRL_DIRECTORY 206 { 207 char *mpszDirectory; 208 char *mpszFilter; 209 ULONG uFlags; 210 /** Associated PID of started vbox_ls tool. */ 211 uint32_t mPID; 212 /** Offset within the current retrieved stdout buffer. */ 213 uint64_t mOffset; 214 } VBOXGUESTCTRL_DIRECTORY, *PVBOXGUESTCTRL_DIRECTORY; 215 typedef std::map< uint32_t, VBOXGUESTCTRL_DIRECTORY > GuestDirectoryMap; 216 typedef std::map< uint32_t, VBOXGUESTCTRL_DIRECTORY >::iterator GuestDirectoryMapIter; 217 typedef std::map< uint32_t, VBOXGUESTCTRL_DIRECTORY >::const_iterator GuestDirectoryMapIterConst; 218 219 int directoryCreateHandle(ULONG *puHandle, const char *pszDirectory, const char *pszFilter, ULONG uFlags); 220 void directoryDestroyHandle(uint32_t uHandle); 221 uint32_t directoryGetPID(uint32_t uHandle); 222 bool directoryHandleExists(uint32_t uHandle); 223 198 224 // Utility functions. 199 int directoryEntryAppend(const char *pszPath, PRTLISTNODE pList);200 int directoryRead(const char *pszDirectory, const char *pszFilter, ULONG uFlags, ULONG *pcObjects, PRTLISTNODE pList);201 225 int prepareExecuteEnv(const char *pszEnv, void **ppvList, uint32_t *pcbList, uint32_t *pcEnv); 202 226 … … 239 263 /** Next upcoming context ID. */ 240 264 volatile uint32_t mNextContextID; 265 /** Next upcoming directory handle ID. */ 266 volatile uint32_t mNextDirectoryID; 241 267 CallbackMap mCallbackMap; 268 GuestDirectoryMap mGuestDirectoryMap; 242 269 GuestProcessMap mGuestProcessMap; 243 270 # endif -
trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp
r37930 r38085 17 17 18 18 #include "GuestImpl.h" 19 #include "GuestCtrlImplPrivate.h" 19 20 20 21 #include "Global.h" … … 485 486 AssertPtr(pGuest); 486 487 487 488 489 #if 0490 488 /* Does our source file exist? */ 491 if (!RTFileExists(aTask->strSource.c_str())) 492 { 493 rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress, 494 Guest::tr("Source file \"%s\" does not exist, or is not a file"), 495 aTask->strSource.c_str()); 496 } 497 else 498 { 499 RTFILE fileSource; 500 int vrc = RTFileOpen(&fileSource, aTask->strSource.c_str(), 501 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE); 502 if (RT_FAILURE(vrc)) 489 BOOL fFileExists; 490 rc = pGuest->FileExists(Bstr(aTask->strSource).raw(), 491 Bstr(aTask->strUserName).raw(), Bstr(aTask->strPassword).raw(), 492 &fFileExists); 493 if (SUCCEEDED(rc)) 494 { 495 if (!fFileExists) 496 rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress, 497 Guest::tr("Source file \"%s\" does not exist, or is not a file"), 498 aTask->strSource.c_str()); 499 } 500 501 /* Query file size to make an estimate for our progress object. */ 502 if (SUCCEEDED(rc)) 503 { 504 LONG64 lFileSize; 505 rc = pGuest->FileQuerySize(Bstr(aTask->strSource).raw(), 506 Bstr(aTask->strUserName).raw(), Bstr(aTask->strPassword).raw(), 507 &lFileSize); 508 if (FAILED(rc)) 509 rc = TaskGuest::setProgressErrorInfo(rc, aTask->progress, pGuest); 510 511 com::SafeArray<IN_BSTR> args; 512 com::SafeArray<IN_BSTR> env; 513 514 if (SUCCEEDED(rc)) 503 515 { 504 rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress, 505 Guest::tr("Could not open source file \"%s\" for reading (%Rrc)"), 506 aTask->strSource.c_str(), vrc); 507 } 508 else 509 { 510 uint64_t cbSize; 511 vrc = RTFileGetSize(fileSource, &cbSize); 512 if (RT_FAILURE(vrc)) 516 /* 517 * Prepare tool command line. 518 */ 519 char szSource[RTPATH_MAX]; 520 if (RTStrPrintf(szSource, sizeof(szSource), "%s", aTask->strSource.c_str()) <= sizeof(szSource) - 1) 513 521 { 514 rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress, 515 Guest::tr("Could not query file size of \"%s\" (%Rrc)"), 516 aTask->strSource.c_str(), vrc); 522 /* 523 * Normalize path slashes, based on the detected guest. 524 */ 525 Utf8Str osType = mData.mOSTypeId; 526 if ( osType.contains("Microsoft", Utf8Str::CaseInsensitive) 527 || osType.contains("Windows", Utf8Str::CaseInsensitive)) 528 { 529 /* We have a Windows guest. */ 530 RTPathChangeToDosSlashes(szSource, true /* Force conversion. */); 531 } 532 else /* ... or something which isn't from Redmond ... */ 533 { 534 RTPathChangeToUnixSlashes(szSource, true /* Force conversion. */); 535 } 536 537 args.push_back(Bstr(szSource).raw()); /* Tell our cat tool which file to output. */ 517 538 } 518 539 else 540 rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress, 541 Guest::tr("Error preparing command line")); 542 } 543 544 ComPtr<IProgress> execProgress; 545 ULONG uPID; 546 if (SUCCEEDED(rc)) 547 { 548 LogRel(("Copying file \"%s\" to host \"%s\" (%u bytes) ...\n", 549 aTask->strSource.c_str(), aTask->strDest.c_str(), lFileSize)); 550 551 /* 552 * Okay, since we gathered all stuff we need until now to start the 553 * actual copying, start the guest part now. 554 */ 555 rc = pGuest->ExecuteProcess(Bstr(VBOXSERVICE_TOOL_CAT).raw(), 556 ExecuteProcessFlag_Hidden, 557 ComSafeArrayAsInParam(args), 558 ComSafeArrayAsInParam(env), 559 Bstr(aTask->strUserName).raw(), 560 Bstr(aTask->strPassword).raw(), 561 5 * 1000 /* Wait 5s for getting the process started. */, 562 &uPID, execProgress.asOutParam()); 563 if (FAILED(rc)) 564 rc = TaskGuest::setProgressErrorInfo(rc, aTask->progress, pGuest); 565 } 566 567 if (SUCCEEDED(rc)) 568 { 569 BOOL fCompleted = FALSE; 570 BOOL fCanceled = FALSE; 571 572 RTFILE hFileDest; 573 int vrc = RTFileOpen(&hFileDest, aTask->strDest.c_str(), 574 RTFILE_O_READWRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE); 575 if (RT_FAILURE(vrc)) 576 rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress, 577 Guest::tr("Unable to create/open destination file \"%s\", rc=%Rrc"), 578 aTask->strDest.c_str(), vrc); 579 else 519 580 { 520 com::SafeArray<IN_BSTR> args; 521 com::SafeArray<IN_BSTR> env; 522 523 /* 524 * Prepare tool command line. 525 */ 526 char szOutput[RTPATH_MAX]; 527 if (RTStrPrintf(szOutput, sizeof(szOutput), "--output=%s", aTask->strDest.c_str()) <= sizeof(szOutput) - 1) 581 size_t cbToRead = lFileSize; 582 size_t cbTransfered = 0; 583 SafeArray<BYTE> aOutputData(_64K); 584 while (SUCCEEDED(execProgress->COMGETTER(Completed(&fCompleted)))) 528 585 { 529 /* 530 * Normalize path slashes, based on the detected guest. 531 */ 532 Utf8Str osType = mData.mOSTypeId; 533 if ( osType.contains("Microsoft", Utf8Str::CaseInsensitive) 534 || osType.contains("Windows", Utf8Str::CaseInsensitive)) 586 rc = this->GetProcessOutput(uPID, ProcessOutputFlag_None, 587 10 * 1000 /* Timeout in ms */, 588 _64K, ComSafeArrayAsOutParam(aOutputData)); 589 if (SUCCEEDED(rc)) 535 590 { 536 /* We have a Windows guest. */ 537 RTPathChangeToDosSlashes(szOutput, true /* Force conversion. */); 538 } 539 else /* ... or something which isn't from Redmond ... */ 540 { 541 RTPathChangeToUnixSlashes(szOutput, true /* Force conversion. */); 542 } 543 544 args.push_back(Bstr(szOutput).raw()); /* We want to write a file ... */ 545 } 546 else 547 { 548 rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress, 549 Guest::tr("Error preparing command line")); 550 } 551 552 ComPtr<IProgress> execProgress; 553 ULONG uPID; 554 if (SUCCEEDED(rc)) 555 { 556 LogRel(("Copying file \"%s\" to guest \"%s\" (%u bytes) ...\n", 557 aTask->strSource.c_str(), aTask->strDest.c_str(), cbSize)); 558 /* 559 * Okay, since we gathered all stuff we need until now to start the 560 * actual copying, start the guest part now. 561 */ 562 rc = pGuest->ExecuteProcess(Bstr(VBOXSERVICE_TOOL_CAT).raw(), 563 ExecuteProcessFlag_Hidden 564 | ExecuteProcessFlag_WaitForProcessStartOnly, 565 ComSafeArrayAsInParam(args), 566 ComSafeArrayAsInParam(env), 567 Bstr(aTask->strUserName).raw(), 568 Bstr(aTask->strPassword).raw(), 569 5 * 1000 /* Wait 5s for getting the process started. */, 570 &uPID, execProgress.asOutParam()); 571 if (FAILED(rc)) 572 rc = TaskGuest::setProgressErrorInfo(rc, aTask->progress, pGuest); 573 } 574 575 if (SUCCEEDED(rc)) 576 { 577 BOOL fCompleted = FALSE; 578 BOOL fCanceled = FALSE; 579 580 size_t cbToRead = cbSize; 581 size_t cbTransfered = 0; 582 size_t cbRead; 583 SafeArray<BYTE> aInputData(_64K); 584 while ( SUCCEEDED(execProgress->COMGETTER(Completed(&fCompleted))) 585 && !fCompleted) 586 { 587 if (!cbToRead) 588 cbRead = 0; 589 else 591 if (!aOutputData.size()) 590 592 { 591 vrc = RTFileRead(fileSource, (uint8_t*)aInputData.raw(), 592 RT_MIN(cbToRead, _64K), &cbRead); 593 /* 594 * Some other error occured? There might be a chance that RTFileRead 595 * could not resolve/map the native error code to an IPRT code, so just 596 * print a generic error. 597 */ 598 if (RT_FAILURE(vrc)) 599 { 593 if (cbToRead) 600 594 rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress, 601 Guest::tr("Could not read from file \"%s\" (%Rrc)"), 602 aTask->strSource.c_str(), vrc); 603 break; 604 } 605 } 606 607 /* Resize buffer to reflect amount we just have read. 608 * Size 0 is allowed! */ 609 aInputData.resize(cbRead); 610 611 ULONG uFlags = ProcessInputFlag_None; 612 /* Did we reach the end of the content we want to transfer (last chunk)? */ 613 if ( (cbRead < _64K) 614 /* Did we reach the last block which is exactly _64K? */ 615 || (cbToRead - cbRead == 0) 616 /* ... or does the user want to cancel? */ 617 || ( SUCCEEDED(aTask->progress->COMGETTER(Canceled(&fCanceled))) 618 && fCanceled) 619 ) 620 { 621 uFlags |= ProcessInputFlag_EndOfFile; 622 } 623 624 /* Transfer the current chunk ... */ 625 ULONG uBytesWritten; 626 rc = pGuest->SetProcessInput(uPID, uFlags, 627 10 * 1000 /* Wait 10s for getting the input data transfered. */, 628 ComSafeArrayAsInParam(aInputData), &uBytesWritten); 629 if (FAILED(rc)) 630 { 631 rc = TaskGuest::setProgressErrorInfo(rc, aTask->progress, pGuest); 595 Guest::tr("Unexpected end of file \"%s\" (%u bytes left)"), 596 aTask->strSource.c_str(), cbToRead); 632 597 break; 633 598 } 634 599 635 Assert(cbRead <= cbToRead); 636 Assert(cbToRead >= cbRead); 637 cbToRead -= cbRead; 638 639 cbTransfered += uBytesWritten; 640 Assert(cbTransfered <= cbSize); 641 aTask->progress->SetCurrentOperationProgress(cbTransfered / (cbSize / 100.0)); 642 643 /* End of file reached? */ 644 if (cbToRead == 0) 645 break; 646 647 /* Did the user cancel the operation above? */ 648 if (fCanceled) 649 break; 650 651 /* Progress canceled by Main API? */ 652 if ( SUCCEEDED(execProgress->COMGETTER(Canceled(&fCanceled))) 653 && fCanceled) 600 vrc = RTFileWrite(hFileDest, aOutputData.raw(), aOutputData.size(), NULL /* No partial writes */); 601 if (RT_FAILURE(vrc)) 654 602 { 655 603 rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress, 656 Guest::tr(" Copy operation of file \"%s\" was canceled on guest side"),657 aTask->strSource.c_str() );604 Guest::tr("Error writing to file \"%s\" (%u bytes left), rc=%Rrc"), 605 aTask->strSource.c_str(), cbToRead, vrc); 658 606 break; 659 607 } 608 609 cbToRead -= aOutputData.size(); 610 cbTransfered += aOutputData.size(); 611 612 aTask->progress->SetCurrentOperationProgress(cbTransfered / (lFileSize / 100.0)); 660 613 } 661 662 if (SUCCEEDED(rc)) 614 else 663 615 { 664 /* 665 * If we got here this means the started process either was completed, 666 * canceled or we simply got all stuff transferred. 667 */ 668 ExecuteProcessStatus_T retStatus; 669 ULONG uRetExitCode; 670 rc = pGuest->waitForProcessStatusChange(uPID, &retStatus, &uRetExitCode, 10 * 1000 /* 10s timeout. */); 671 if (FAILED(rc)) 672 { 673 rc = TaskGuest::setProgressErrorInfo(rc, aTask->progress, pGuest); 674 } 675 else 676 { 677 if ( uRetExitCode != 0 678 || retStatus != ExecuteProcessStatus_TerminatedNormally) 679 { 680 rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress, 681 Guest::tr("Guest reported error %u while copying file \"%s\" to \"%s\""), 682 uRetExitCode, aTask->strSource.c_str(), aTask->strDest.c_str()); 683 } 684 } 685 } 686 687 if (SUCCEEDED(rc)) 688 { 689 if (fCanceled) 690 { 691 /* 692 * In order to make the progress object to behave nicely, we also have to 693 * notify the object with a complete event when it's canceled. 694 */ 695 aTask->progress->notifyComplete(VBOX_E_IPRT_ERROR, 696 COM_IIDOF(IGuest), 697 Guest::getStaticComponentName(), 698 Guest::tr("Copying file \"%s\" canceled"), aTask->strSource.c_str()); 699 } 700 else 701 { 702 /* 703 * Even if we succeeded until here make sure to check whether we really transfered 704 * everything. 705 */ 706 if ( cbSize > 0 707 && cbTransfered == 0) 708 { 709 /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write 710 * to the destination -> access denied. */ 711 rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress, 712 Guest::tr("Access denied when copying file \"%s\" to \"%s\""), 713 aTask->strSource.c_str(), aTask->strDest.c_str()); 714 } 715 else if (cbTransfered < cbSize) 716 { 717 /* If we did not copy all let the user know. */ 718 rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress, 719 Guest::tr("Copying file \"%s\" failed (%u/%u bytes transfered)"), 720 aTask->strSource.c_str(), cbTransfered, cbSize); 721 } 722 else /* Yay, all went fine! */ 723 aTask->progress->notifyComplete(S_OK); 724 } 616 rc = TaskGuest::setProgressErrorInfo(rc, aTask->progress, pGuest); 617 break; 725 618 } 726 619 } 620 621 if (SUCCEEDED(rc)) 622 aTask->progress->notifyComplete(S_OK); 623 624 RTFileClose(hFileDest); 727 625 } 728 RTFileClose(fileSource);729 626 } 730 627 } 731 #endif732 628 } 733 629 catch (HRESULT aRC) … … 2874 2770 ULONG aFlags, IProgress **aProgress) 2875 2771 { 2876 ReturnComNotImplemented();2877 }2878 2879 STDMETHODIMP Guest::CopyToGuest(IN_BSTR aSource, IN_BSTR aDest,2880 IN_BSTR aUserName, IN_BSTR aPassword,2881 ULONG aFlags, IProgress **aProgress)2882 {2883 2772 #ifndef VBOX_WITH_GUEST_CONTROL 2884 2773 ReturnComNotImplemented(); … … 2915 2804 2916 2805 rc = progress->init(static_cast<IGuest*>(this), 2917 Bstr(tr("Copying file from host to guest")).raw(),2806 Bstr(tr("Copying file from guest to host")).raw(), 2918 2807 TRUE /* aCancelable */); 2919 2808 if (FAILED(rc)) throw rc; 2920 2809 2921 2810 /* Initialize our worker task. */ 2922 TaskGuest *pTask = new TaskGuest(TaskGuest::CopyFile ToGuest, this, progress);2811 TaskGuest *pTask = new TaskGuest(TaskGuest::CopyFileFromGuest, this, progress); 2923 2812 AssertPtr(pTask); 2924 2813 std::auto_ptr<TaskGuest> task(pTask); … … 2952 2841 } 2953 2842 2843 STDMETHODIMP Guest::CopyToGuest(IN_BSTR aSource, IN_BSTR aDest, 2844 IN_BSTR aUserName, IN_BSTR aPassword, 2845 ULONG aFlags, IProgress **aProgress) 2846 { 2847 #ifndef VBOX_WITH_GUEST_CONTROL 2848 ReturnComNotImplemented(); 2849 #else /* VBOX_WITH_GUEST_CONTROL */ 2850 CheckComArgStrNotEmptyOrNull(aSource); 2851 CheckComArgStrNotEmptyOrNull(aDest); 2852 CheckComArgStrNotEmptyOrNull(aUserName); 2853 CheckComArgStrNotEmptyOrNull(aPassword); 2854 CheckComArgOutPointerValid(aProgress); 2855 2856 AutoCaller autoCaller(this); 2857 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 2858 2859 /* Validate flags. */ 2860 if (aFlags != CopyFileFlag_None) 2861 { 2862 if ( !(aFlags & CopyFileFlag_Recursive) 2863 && !(aFlags & CopyFileFlag_Update) 2864 && !(aFlags & CopyFileFlag_FollowLinks)) 2865 { 2866 return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags); 2867 } 2868 } 2869 2870 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 2871 2872 HRESULT rc = S_OK; 2873 2874 ComObjPtr<Progress> progress; 2875 try 2876 { 2877 /* Create the progress object. */ 2878 progress.createObject(); 2879 2880 rc = progress->init(static_cast<IGuest*>(this), 2881 Bstr(tr("Copying file from host to guest")).raw(), 2882 TRUE /* aCancelable */); 2883 if (FAILED(rc)) throw rc; 2884 2885 /* Initialize our worker task. */ 2886 TaskGuest *pTask = new TaskGuest(TaskGuest::CopyFileToGuest, this, progress); 2887 AssertPtr(pTask); 2888 std::auto_ptr<TaskGuest> task(pTask); 2889 2890 /* Assign data - aSource is the source file on the host, 2891 * aDest reflects the full path on the guest. */ 2892 task->strSource = (Utf8Str(aSource)); 2893 task->strDest = (Utf8Str(aDest)); 2894 task->strUserName = (Utf8Str(aUserName)); 2895 task->strPassword = (Utf8Str(aPassword)); 2896 task->uFlags = aFlags; 2897 2898 rc = task->startThread(); 2899 if (FAILED(rc)) throw rc; 2900 2901 /* Don't destruct on success. */ 2902 task.release(); 2903 } 2904 catch (HRESULT aRC) 2905 { 2906 rc = aRC; 2907 } 2908 2909 if (SUCCEEDED(rc)) 2910 { 2911 /* Return progress to the caller. */ 2912 progress.queryInterfaceTo(aProgress); 2913 } 2914 return rc; 2915 #endif /* VBOX_WITH_GUEST_CONTROL */ 2916 } 2917 2954 2918 STDMETHODIMP Guest::DirectoryClose(ULONG aHandle) 2955 2919 { 2920 #ifndef VBOX_WITH_GUEST_CONTROL 2956 2921 ReturnComNotImplemented(); 2922 #else /* VBOX_WITH_GUEST_CONTROL */ 2923 using namespace guestControl; 2924 2925 if (directoryHandleExists(aHandle)) 2926 { 2927 directoryDestroyHandle(aHandle); 2928 return S_OK; 2929 } 2930 2931 return setError(VBOX_E_IPRT_ERROR, 2932 Guest::tr("Directory handle is invalid")); 2933 #endif 2957 2934 } 2958 2935 … … 3087 3064 } 3088 3065 3066 /** 3067 * Creates a new directory handle ID and returns it. 3068 * 3069 * @return IPRT status code. 3070 * @param puHandle Pointer where the handle gets stored to. 3071 * @param pszDirectory Directory the handle is assigned to. 3072 * @param pszFilter Directory filter. Optional. 3073 * @param uFlags Directory open flags. 3074 * 3075 */ 3076 int Guest::directoryCreateHandle(ULONG *puHandle, const char *pszDirectory, const char *pszFilter, ULONG uFlags) 3077 { 3078 AssertPtrReturn(puHandle, VERR_INVALID_POINTER); 3079 AssertPtrReturn(pszDirectory, VERR_INVALID_POINTER); 3080 /* pszFilter is optional. */ 3081 3082 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 3083 3084 int rc = VERR_TOO_MUCH_DATA; 3085 for (uint32_t i = 0; i < UINT32_MAX; i++) 3086 { 3087 /* Create a new context ID ... */ 3088 uint32_t uHandleTry = ASMAtomicIncU32(&mNextDirectoryID); 3089 GuestDirectoryMapIter it = mGuestDirectoryMap.find(uHandleTry); 3090 if (mGuestDirectoryMap.end() == it) 3091 { 3092 rc = VINF_SUCCESS; 3093 if (!RTStrAPrintf(&mGuestDirectoryMap[uHandleTry].mpszDirectory, pszDirectory)) 3094 rc = VERR_NO_MEMORY; 3095 else 3096 { 3097 /* Filter is optional. */ 3098 if (pszFilter) 3099 { 3100 if (!RTStrAPrintf(&mGuestDirectoryMap[uHandleTry].mpszFilter, pszFilter)) 3101 rc = VERR_NO_MEMORY; 3102 } 3103 3104 if (RT_SUCCESS(rc)) 3105 { 3106 mGuestDirectoryMap[uHandleTry].uFlags = uFlags; 3107 *puHandle = uHandleTry; 3108 3109 break; 3110 } 3111 } 3112 3113 if (RT_FAILURE(rc)) 3114 break; 3115 3116 Assert(mGuestDirectoryMap.size()); 3117 } 3118 } 3119 3120 return rc; 3121 } 3122 3123 void Guest::directoryDestroyHandle(uint32_t uHandle) 3124 { 3125 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 3126 3127 GuestDirectoryMapIter it = mGuestDirectoryMap.find(uHandle); 3128 if (it != mGuestDirectoryMap.end()) 3129 { 3130 RTStrFree(it->second.mpszDirectory); 3131 RTStrFree(it->second.mpszFilter); 3132 3133 /* Remove callback context (not used anymore). */ 3134 mGuestDirectoryMap.erase(it); 3135 } 3136 } 3137 3138 uint32_t Guest::directoryGetPID(uint32_t uHandle) 3139 { 3140 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 3141 3142 GuestDirectoryMapIter it = mGuestDirectoryMap.find(uHandle); 3143 if (it != mGuestDirectoryMap.end()) 3144 return it->second.mPID; 3145 3146 return 0; 3147 } 3148 3149 bool Guest::directoryHandleExists(uint32_t uHandle) 3150 { 3151 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 3152 3153 GuestDirectoryMapIter it = mGuestDirectoryMap.find(uHandle); 3154 if (it != mGuestDirectoryMap.end()) 3155 return true; 3156 3157 return false; 3158 } 3159 3089 3160 STDMETHODIMP Guest::DirectoryOpen(IN_BSTR aDirectory, IN_BSTR aFilter, 3090 3161 ULONG aFlags, IN_BSTR aUserName, IN_BSTR aPassword, 3091 3162 ULONG *aHandle) 3092 {3093 ReturnComNotImplemented();3094 }3095 3096 STDMETHODIMP Guest::DirectoryRead(ULONG aHandle, IGuestDirEntry **aDirEntry)3097 {3098 ReturnComNotImplemented();3099 }3100 3101 STDMETHODIMP Guest::FileExists(IN_BSTR aFile, IN_BSTR aUserName, IN_BSTR aPassword, BOOL *aExists)3102 3163 { 3103 3164 #ifndef VBOX_WITH_GUEST_CONTROL … … 3106 3167 using namespace guestControl; 3107 3168 3108 return VBOX_E_NOT_SUPPORTED; 3169 CheckComArgStrNotEmptyOrNull(aDirectory); 3170 CheckComArgNotNull(aHandle); 3171 3172 /* Do not allow anonymous executions (with system rights). */ 3173 if (RT_UNLIKELY((aUserName) == NULL || *(aUserName) == '\0')) 3174 return setError(E_INVALIDARG, tr("No user name specified")); 3175 3176 return directoryOpenInternal(aDirectory, aFilter, 3177 aFlags, 3178 aUserName, aPassword, 3179 aHandle, NULL /* rc */); 3109 3180 #endif 3110 3181 } 3111 3182 3112 STDMETHODIMP Guest::FileQuerySize(IN_BSTR aFile, IN_BSTR aUserName, IN_BSTR aPassword, LONG64 *aSize) 3183 HRESULT Guest::directoryOpenInternal(IN_BSTR aDirectory, IN_BSTR aFilter, 3184 ULONG aFlags, 3185 IN_BSTR aUserName, IN_BSTR aPassword, 3186 ULONG *aHandle, int *pRC) 3113 3187 { 3114 3188 #ifndef VBOX_WITH_GUEST_CONTROL … … 3117 3191 using namespace guestControl; 3118 3192 3119 return VBOX_E_NOT_SUPPORTED; 3193 CheckComArgStrNotEmptyOrNull(aDirectory); 3194 CheckComArgNotNull(aHandle); 3195 3196 AutoCaller autoCaller(this); 3197 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 3198 3199 /* Validate flags. No flags supported yet. */ 3200 if (aFlags != DirectoryOpenFlag_None) 3201 return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags); 3202 3203 HRESULT rc = S_OK; 3204 try 3205 { 3206 Utf8Str Utf8Directory(aDirectory); 3207 Utf8Str Utf8Filter(aFilter); 3208 Utf8Str Utf8UserName(aUserName); 3209 Utf8Str Utf8Password(aPassword); 3210 3211 com::SafeArray<IN_BSTR> args; 3212 com::SafeArray<IN_BSTR> env; 3213 3214 /* 3215 * Prepare tool command line. 3216 */ 3217 3218 /* We need to get output which is machine-readable in form 3219 * of "key=value\0..key=value\0\0". */ 3220 args.push_back(Bstr("--machinereadable").raw()); 3221 3222 /* We want the long output format. Handy for getting a lot of 3223 * details we could (should?) use (later). */ 3224 args.push_back(Bstr("-l").raw()); 3225 3226 /* As we want to keep this stuff simple we don't do recursive (-R) 3227 * or dereferencing (--dereference) lookups here. This has to be done by 3228 * the user. */ 3229 3230 /* Construct and hand in actual directory name + filter we want to open. */ 3231 char *pszDirectoryFinal; 3232 int cbRet; 3233 if (Utf8Filter.isEmpty()) 3234 cbRet = RTStrAPrintf(&pszDirectoryFinal, "%s", Utf8Directory.c_str()); 3235 else 3236 cbRet = RTStrAPrintf(&pszDirectoryFinal, "%s/%s", 3237 Utf8Directory.c_str(), Utf8Filter.c_str()); 3238 if (!cbRet) 3239 return setError(E_OUTOFMEMORY, tr("Out of memory while allocating final directory")); 3240 3241 args.push_back(Bstr(pszDirectoryFinal).raw()); /* The directory we want to open. */ 3242 3243 /* 3244 * Execute guest process. 3245 */ 3246 ComPtr<IProgress> progressExec; 3247 ULONG uPID; 3248 3249 rc = ExecuteProcess(Bstr(VBOXSERVICE_TOOL_LS).raw(), 3250 ExecuteProcessFlag_Hidden, 3251 ComSafeArrayAsInParam(args), 3252 ComSafeArrayAsInParam(env), 3253 Bstr(Utf8UserName).raw(), 3254 Bstr(Utf8Password).raw(), 3255 30 * 1000 /* Wait 30s for getting the process started. */, 3256 &uPID, progressExec.asOutParam()); 3257 3258 RTStrFree(pszDirectoryFinal); 3259 3260 if (SUCCEEDED(rc)) 3261 { 3262 /* Wait for process to exit ... */ 3263 rc = progressExec->WaitForCompletion(-1); 3264 if (FAILED(rc)) return rc; 3265 3266 BOOL fCompleted = FALSE; 3267 BOOL fCanceled = FALSE; 3268 progressExec->COMGETTER(Completed)(&fCompleted); 3269 if (!fCompleted) 3270 progressExec->COMGETTER(Canceled)(&fCanceled); 3271 3272 if (fCompleted) 3273 { 3274 ExecuteProcessStatus_T retStatus; 3275 ULONG uRetExitCode, uRetFlags; 3276 if (SUCCEEDED(rc)) 3277 { 3278 rc = GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &retStatus); 3279 if (SUCCEEDED(rc) && uRetExitCode != 0) 3280 { 3281 rc = setError(VBOX_E_IPRT_ERROR, 3282 tr("Error %u while opening guest directory"), uRetExitCode); 3283 } 3284 } 3285 } 3286 else if (fCanceled) 3287 rc = setError(VBOX_E_IPRT_ERROR, 3288 tr("Guest directory opening was aborted")); 3289 else 3290 AssertReleaseMsgFailed(("Guest directory opening neither completed nor canceled!?\n")); 3291 3292 if (SUCCEEDED(rc)) 3293 { 3294 /* Assign new directory handle ID. */ 3295 int vrc = directoryCreateHandle(aHandle, 3296 Utf8Directory.c_str(), 3297 Utf8Filter.isEmpty() ? NULL : Utf8Filter.c_str(), 3298 aFlags); 3299 if (RT_FAILURE(vrc)) 3300 { 3301 rc = setError(VBOX_E_IPRT_ERROR, 3302 tr("Unable to create guest directory handle (%Rrc)"), vrc); 3303 } 3304 } 3305 } 3306 } 3307 catch (std::bad_alloc &) 3308 { 3309 rc = E_OUTOFMEMORY; 3310 } 3311 return rc; 3312 #endif /* VBOX_WITH_GUEST_CONTROL */ 3313 } 3314 3315 STDMETHODIMP Guest::DirectoryRead(ULONG aHandle, IGuestDirEntry **aDirEntry) 3316 { 3317 #ifndef VBOX_WITH_GUEST_CONTROL 3318 ReturnComNotImplemented(); 3319 #else /* VBOX_WITH_GUEST_CONTROL */ 3320 using namespace guestControl; 3321 3322 uint32_t uPID = directoryGetPID(aHandle); 3323 if (uPID) 3324 { 3325 SafeArray<BYTE> aOutputData; 3326 ULONG cbOutputData = 0; 3327 3328 HRESULT rc = this->GetProcessOutput(uPID, ProcessOutputFlag_None, 3329 30 * 1000 /* Timeout in ms */, 3330 _64K, ComSafeArrayAsOutParam(aOutputData)); 3331 if (SUCCEEDED(rc)) 3332 { 3333 3334 } 3335 3336 return rc; 3337 } 3338 3339 return setError(VBOX_E_IPRT_ERROR, 3340 Guest::tr("Directory handle is invalid")); 3341 #endif 3342 } 3343 3344 STDMETHODIMP Guest::FileExists(IN_BSTR aFile, IN_BSTR aUserName, IN_BSTR aPassword, BOOL *aExists) 3345 { 3346 #ifndef VBOX_WITH_GUEST_CONTROL 3347 ReturnComNotImplemented(); 3348 #else /* VBOX_WITH_GUEST_CONTROL */ 3349 using namespace guestControl; 3350 3351 CheckComArgStrNotEmptyOrNull(aFile); 3352 3353 /* Do not allow anonymous executions (with system rights). */ 3354 if (RT_UNLIKELY((aUserName) == NULL || *(aUserName) == '\0')) 3355 return setError(E_INVALIDARG, tr("No user name specified")); 3356 3357 return fileExistsInternal(aFile, 3358 aUserName, aPassword, aExists, 3359 NULL /* rc */); 3360 #endif 3361 } 3362 3363 HRESULT Guest::fileExistsInternal(IN_BSTR aFile, IN_BSTR aUserName, IN_BSTR aPassword, BOOL *aExists, int *pRC) 3364 { 3365 #ifndef VBOX_WITH_GUEST_CONTROL 3366 ReturnComNotImplemented(); 3367 #else /* VBOX_WITH_GUEST_CONTROL */ 3368 using namespace guestControl; 3369 3370 CheckComArgStrNotEmptyOrNull(aFile); 3371 3372 AutoCaller autoCaller(this); 3373 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 3374 3375 HRESULT rc = S_OK; 3376 try 3377 { 3378 Utf8Str Utf8File(aFile); 3379 Utf8Str Utf8UserName(aUserName); 3380 Utf8Str Utf8Password(aPassword); 3381 3382 com::SafeArray<IN_BSTR> args; 3383 com::SafeArray<IN_BSTR> env; 3384 3385 /* 3386 * Prepare tool command line. 3387 */ 3388 3389 /* Only the actual file name to chekc is needed for now. */ 3390 args.push_back(Bstr(Utf8File).raw()); 3391 3392 /* 3393 * Execute guest process. 3394 */ 3395 ComPtr<IProgress> progressExec; 3396 ULONG uPID; 3397 3398 rc = ExecuteProcess(Bstr(VBOXSERVICE_TOOL_STAT).raw(), 3399 ExecuteProcessFlag_Hidden, 3400 ComSafeArrayAsInParam(args), 3401 ComSafeArrayAsInParam(env), 3402 Bstr(Utf8UserName).raw(), 3403 Bstr(Utf8Password).raw(), 3404 30 * 1000 /* Wait 30s for getting the process started. */, 3405 &uPID, progressExec.asOutParam()); 3406 3407 if (SUCCEEDED(rc)) 3408 { 3409 /* Wait for process to exit ... */ 3410 rc = progressExec->WaitForCompletion(-1); 3411 if (FAILED(rc)) return rc; 3412 3413 BOOL fCompleted = FALSE; 3414 BOOL fCanceled = FALSE; 3415 progressExec->COMGETTER(Completed)(&fCompleted); 3416 if (!fCompleted) 3417 progressExec->COMGETTER(Canceled)(&fCanceled); 3418 3419 if (fCompleted) 3420 { 3421 ExecuteProcessStatus_T retStatus; 3422 ULONG uRetExitCode, uRetFlags; 3423 if (SUCCEEDED(rc)) 3424 { 3425 rc = GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &retStatus); 3426 if (SUCCEEDED(rc)) 3427 { 3428 *aExists = uRetExitCode == 0 ? TRUE : FALSE; 3429 } 3430 else 3431 rc = setError(VBOX_E_IPRT_ERROR, 3432 tr("Error %u while checking for existence of file \"%s\""), 3433 uRetExitCode, Utf8File.c_str()); 3434 } 3435 } 3436 else if (fCanceled) 3437 rc = setError(VBOX_E_IPRT_ERROR, 3438 tr("Checking for file existence was aborted")); 3439 else 3440 AssertReleaseMsgFailed(("Checking for file existence neither completed nor canceled!?\n")); 3441 } 3442 } 3443 catch (std::bad_alloc &) 3444 { 3445 rc = E_OUTOFMEMORY; 3446 } 3447 return rc; 3448 #endif 3449 } 3450 3451 STDMETHODIMP Guest::FileQuerySize(IN_BSTR aFile, IN_BSTR aUserName, IN_BSTR aPassword, LONG64 *aSize) 3452 { 3453 #ifndef VBOX_WITH_GUEST_CONTROL 3454 ReturnComNotImplemented(); 3455 #else /* VBOX_WITH_GUEST_CONTROL */ 3456 using namespace guestControl; 3457 3458 CheckComArgStrNotEmptyOrNull(aFile); 3459 3460 /* Do not allow anonymous executions (with system rights). */ 3461 if (RT_UNLIKELY((aUserName) == NULL || *(aUserName) == '\0')) 3462 return setError(E_INVALIDARG, tr("No user name specified")); 3463 3464 return fileQuerySizeInternal(aFile, 3465 aUserName, aPassword, aSize, 3466 NULL /* rc */); 3467 #endif 3468 } 3469 3470 HRESULT Guest::fileQuerySizeInternal(IN_BSTR aFile, IN_BSTR aUserName, IN_BSTR aPassword, LONG64 *aSize, int *pRC) 3471 { 3472 #ifndef VBOX_WITH_GUEST_CONTROL 3473 ReturnComNotImplemented(); 3474 #else /* VBOX_WITH_GUEST_CONTROL */ 3475 using namespace guestControl; 3476 3477 CheckComArgStrNotEmptyOrNull(aFile); 3478 3479 AutoCaller autoCaller(this); 3480 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 3481 3482 HRESULT rc = S_OK; 3483 try 3484 { 3485 Utf8Str Utf8File(aFile); 3486 Utf8Str Utf8UserName(aUserName); 3487 Utf8Str Utf8Password(aPassword); 3488 3489 com::SafeArray<IN_BSTR> args; 3490 com::SafeArray<IN_BSTR> env; 3491 3492 /* 3493 * Prepare tool command line. 3494 */ 3495 3496 /* We need to get output which is machine-readable in form 3497 * of "key=value\0..key=value\0\0". */ 3498 args.push_back(Bstr("--machinereadable").raw()); 3499 3500 /* Only the actual file name to chekc is needed for now. */ 3501 args.push_back(Bstr(Utf8File).raw()); 3502 3503 /* 3504 * Execute guest process. 3505 */ 3506 ComPtr<IProgress> progressExec; 3507 ULONG uPID; 3508 3509 rc = ExecuteProcess(Bstr(VBOXSERVICE_TOOL_STAT).raw(), 3510 ExecuteProcessFlag_Hidden, 3511 ComSafeArrayAsInParam(args), 3512 ComSafeArrayAsInParam(env), 3513 Bstr(Utf8UserName).raw(), 3514 Bstr(Utf8Password).raw(), 3515 30 * 1000 /* Wait 30s for getting the process started. */, 3516 &uPID, progressExec.asOutParam()); 3517 3518 if (SUCCEEDED(rc)) 3519 { 3520 /* Wait for process to exit ... */ 3521 rc = progressExec->WaitForCompletion(-1); 3522 if (FAILED(rc)) return rc; 3523 3524 BOOL fCompleted = FALSE; 3525 BOOL fCanceled = FALSE; 3526 progressExec->COMGETTER(Completed)(&fCompleted); 3527 if (!fCompleted) 3528 progressExec->COMGETTER(Canceled)(&fCanceled); 3529 3530 if (fCompleted) 3531 { 3532 ExecuteProcessStatus_T retStatus; 3533 ULONG uRetExitCode, uRetFlags; 3534 if (SUCCEEDED(rc)) 3535 { 3536 rc = GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &retStatus); 3537 if (SUCCEEDED(rc)) 3538 { 3539 if (uRetExitCode == 0) 3540 { 3541 /* Get file size from output stream. */ 3542 SafeArray<BYTE> aOutputData; 3543 ULONG cbOutputData = 0; 3544 3545 GuestProcessStream guestStream; 3546 int vrc = VINF_SUCCESS; 3547 for (;;) 3548 { 3549 rc = this->GetProcessOutput(uPID, ProcessOutputFlag_None, 3550 30 * 1000 /* Timeout in ms */, 3551 _64K, ComSafeArrayAsOutParam(aOutputData)); 3552 /** @todo Do stream header validation! */ 3553 if ( SUCCEEDED(rc) 3554 && aOutputData.size()) 3555 { 3556 vrc = guestStream.AddData(aOutputData.raw(), aOutputData.size()); 3557 if (RT_UNLIKELY(RT_FAILURE(vrc))) 3558 rc = setError(VBOX_E_IPRT_ERROR, 3559 tr("Error while adding guest output to stream buffer (%Rrc)"), vrc); 3560 } 3561 else 3562 break; 3563 } 3564 3565 if (SUCCEEDED(rc)) 3566 { 3567 vrc = guestStream.Parse(); 3568 if ( RT_SUCCESS(vrc) 3569 || vrc == VERR_MORE_DATA) 3570 { 3571 int64_t iVal; 3572 vrc = guestStream.GetInt64Ex("st_size", &iVal); 3573 if (RT_SUCCESS(vrc)) 3574 *aSize = iVal; 3575 else 3576 rc = setError(VBOX_E_IPRT_ERROR, 3577 tr("Unable to retrieve file size (%Rrc)"), vrc); 3578 } 3579 else 3580 rc = setError(VBOX_E_IPRT_ERROR, 3581 tr("Error while parsing guest output (%Rrc)"), vrc); 3582 } 3583 } 3584 else 3585 rc = setError(VBOX_E_IPRT_ERROR, 3586 tr("Error querying file size for file \"%s\" (exit code %u)"), 3587 Utf8File.c_str(), uRetExitCode); 3588 } 3589 } 3590 } 3591 else if (fCanceled) 3592 rc = setError(VBOX_E_IPRT_ERROR, 3593 tr("Checking for file existence was aborted")); 3594 else 3595 AssertReleaseMsgFailed(("Checking for file existence neither completed nor canceled!?\n")); 3596 } 3597 } 3598 catch (std::bad_alloc &) 3599 { 3600 rc = E_OUTOFMEMORY; 3601 } 3602 return rc; 3120 3603 #endif 3121 3604 } -
trunk/src/VBox/Main/testcase/tstGuestCtrlParseBuffer.cpp
r37974 r38085 54 54 { 55 55 /* Invalid stuff. */ 56 { NULL, 0, 0, 0, 0, VERR_INVALID_POINTER }, 57 { NULL, 512, 0, 0, 0, VERR_INVALID_POINTER }, 58 { "", 0, 0, 0, 0, VERR_INVALID_PARAMETER }, 59 { "", 0, 0, 0, 0, VERR_INVALID_PARAMETER }, 60 { "foo=bar1", 0, 0, 0, 0, VERR_INVALID_PARAMETER }, 61 { "foo=bar2", 0, 50, 50, 0, VERR_INVALID_PARAMETER }, 62 /* Incomplete buffer (missing \0 termination). */ 63 { "", 1, 0, 0, 0, VERR_MORE_DATA }, 64 { "\0", 1, 0, 0, 0, VERR_MORE_DATA }, 65 { szUnterm1, 5, 0, 0, 0, VERR_MORE_DATA }, 66 { "foo1", sizeof("foo1"), 0, 0, 0, VERR_MORE_DATA }, 67 { szUnterm2, 8, 0, 0, 0, VERR_MORE_DATA }, 56 { NULL, 0, 0, 0, 0, VERR_INVALID_POINTER }, 57 { NULL, 512, 0, 0, 0, VERR_INVALID_POINTER }, 58 { "", 0, 0, 0, 0, VERR_INVALID_PARAMETER }, 59 { "", 0, 0, 0, 0, VERR_INVALID_PARAMETER }, 60 { "foo=bar1", 0, 0, 0, 0, VERR_INVALID_PARAMETER }, 61 { "foo=bar2", 0, 50, 50, 0, VERR_INVALID_PARAMETER }, 62 /* Empty buffers. */ 63 { "", 1, 0, 1, 0, VERR_MORE_DATA }, 64 { "\0", 1, 0, 1, 0, VERR_MORE_DATA }, 68 65 /* Incomplete buffer (missing components). */ 69 { "=bar\0", sizeof("=bar"), 0, 0, 0, VERR_MORE_DATA }, 66 { szUnterm1, 5, 0, 0, 0, VERR_MORE_DATA }, 67 { "foo1", sizeof("foo1"), 0, 0, 0, VERR_MORE_DATA }, 68 { "=bar\0", sizeof("=bar"), 0, 0 , 0, VERR_MORE_DATA }, 70 69 /* Last sequence is incomplete -- new offset should point to it. */ 71 70 { "hug=sub\0incomplete", sizeof("hug=sub\0incomplete"), 0, sizeof("hug=sub"), 1, VERR_MORE_DATA }, 72 71 { "boo=hoo\0baz=boo\0qwer", sizeof("boo=hoo\0baz=boo\0qwer"), 0, sizeof("boo=hoo\0baz=boo"), 2, VERR_MORE_DATA }, 73 72 /* Parsing good stuff. */ 73 { "novalue=", sizeof("novalue="), 0, sizeof("novalue="), 1, VINF_SUCCESS }, 74 { szUnterm2, 8, 0, sizeof(szUnterm2), 1, VINF_SUCCESS }, 74 75 { "foo2=", sizeof("foo2="), 0, sizeof("foo2="), 1, VINF_SUCCESS }, 75 76 { "har=hor", sizeof("har=hor"), 0, sizeof("har=hor"), 1, VINF_SUCCESS }, 76 77 { "foo=bar\0baz=boo", sizeof("foo=bar\0baz=boo"), 0, sizeof("foo=bar\0baz=boo"), 2, VINF_SUCCESS }, 77 78 /* Parsing until a different block (two terminations, returning offset to next block). */ 78 { "off=rab\0\0zab=oob", sizeof("off=rab\0\0zab=oob"), 0, sizeof("zab=oob"), 1, VERR_MORE_DATA } 79 { "off=rab\0a=b\0\0\0\0", sizeof("off=rab\0a=b\0\0\0"), 0, 13, 2, VERR_MORE_DATA }, 80 { "off=rab\0\0zab=oob", sizeof("off=rab\0\0zab=oob"), 0, 9, 1, VERR_MORE_DATA }, 81 { "\0\0\0\0off=rab\0zab=oob\0\0", sizeof("\0\0\0\0off=rab\0zab=oob\0\0"), 0, 1, 0, VERR_MORE_DATA }, 82 { "o2=r2\0z3=o3\0\0f3=g3", sizeof("o2=r2\0z3=o3\0\0f3=g3"), 0, 13, 2, VERR_MORE_DATA } 79 83 }; 80 84 … … 89 93 } aTests2[] = 90 94 { 95 { "\0\0\0\0", sizeof("\0\0\0\0"), 0, VERR_MORE_DATA }, 91 96 { "off=rab\0\0zab=oob", sizeof("off=rab\0\0zab=oob"), 2, VINF_SUCCESS }, 92 97 { "\0\0\0soo=foo\0goo=loo\0\0zab=oob", sizeof("\0\0\0soo=foo\0goo=loo\0\0zab=oob"), 2, VINF_SUCCESS }, 93 { "qoo=uoo\0\0\0\0asdf=\0\0", sizeof("qoo=uoo\0\0\0\0asdf=\0\0"), 2, VINF_SUCCESS }, 94 { "foo=bar\0\0\0\0\0\0", sizeof("foo=bar\0\0\0\0\0\0"), 1, VINF_SUCCESS } 98 { "qoo=uoo\0\0\0\0asdf=\0\0", sizeof("qoo=uoo\0\0\0\0asdf=\0\0"), 2, VERR_MORE_DATA }, 99 { "foo=bar\0\0\0\0\0\0", sizeof("foo=bar\0\0\0\0\0\0"), 1, VERR_MORE_DATA }, 100 { "qwer=cvbnr\0\0\0gui=uig\0\0\0", sizeof("qwer=cvbnr\0\0\0gui=uig\0\0\0"), 2, VERR_MORE_DATA } 95 101 }; 96 102 … … 110 116 const char *pszEnd = pszStart; 111 117 112 /* Search and of current pair (key=value\0). */118 /* Search end of current pair (key=value\0). */ 113 119 while (uCur++ < cbData) 114 120 { … … 119 125 120 126 size_t uPairLen = pszEnd - pszStart; 121 if ( *pszEnd != '\0' 122 || !uPairLen) 123 { 124 rc = VERR_MORE_DATA; 125 break; 126 } 127 128 const char *pszSep = pszStart; 129 while ( *pszSep != '=' 130 && pszSep != pszEnd) 131 { 132 pszSep++; 133 } 134 135 if ( pszSep == pszStart 136 || pszSep == pszEnd) 137 { 138 rc = VERR_MORE_DATA; 139 break; 140 } 141 142 size_t uKeyLen = pszSep - pszStart; 143 size_t uValLen = pszEnd - (pszSep + 1); 144 145 /* Get key (if present). */ 146 if (uKeyLen) 147 { 148 Assert(pszSep > pszStart); 149 char *pszKey = (char*)RTMemAllocZ(uKeyLen + 1); 150 if (!pszKey) 151 { 152 rc = VERR_NO_MEMORY; 127 if (uPairLen) 128 { 129 const char *pszSep = pszStart; 130 while ( *pszSep != '=' 131 && pszSep != pszEnd) 132 { 133 pszSep++; 134 } 135 136 /* No separator found (or incomplete key=value pair)? */ 137 if ( pszSep == pszStart 138 || pszSep == pszEnd) 139 { 140 *puOffset = uCur - uPairLen - 1; 141 rc = VERR_MORE_DATA; 142 } 143 144 if (RT_FAILURE(rc)) 153 145 break; 154 } 155 memcpy(pszKey, pszStart, uKeyLen); 156 157 mapBuf[RTCString(pszKey)].pszValue = NULL; 158 159 /* Get value (if present). */ 160 if (uValLen) 161 { 162 Assert(pszEnd > pszSep); 163 char *pszVal = (char*)RTMemAllocZ(uValLen + 1); 164 if (!pszVal) 146 147 size_t uKeyLen = pszSep - pszStart; 148 size_t uValLen = pszEnd - (pszSep + 1); 149 150 /* Get key (if present). */ 151 if (uKeyLen) 152 { 153 Assert(pszSep > pszStart); 154 char *pszKey = (char*)RTMemAllocZ(uKeyLen + 1); 155 if (!pszKey) 165 156 { 166 157 rc = VERR_NO_MEMORY; 167 158 break; 168 159 } 169 memcpy(pszVal, pszSep + 1, uValLen); 170 171 mapBuf[RTCString(pszKey)].pszValue = pszVal; 172 } 173 174 RTMemFree(pszKey); 175 176 *puOffset += uCur - *puOffset; 177 } 160 memcpy(pszKey, pszStart, uKeyLen); 161 162 mapBuf[RTCString(pszKey)].pszValue = NULL; 163 164 /* Get value (if present). */ 165 if (uValLen) 166 { 167 Assert(pszEnd > pszSep); 168 char *pszVal = (char*)RTMemAllocZ(uValLen + 1); 169 if (!pszVal) 170 { 171 rc = VERR_NO_MEMORY; 172 break; 173 } 174 memcpy(pszVal, pszSep + 1, uValLen); 175 176 mapBuf[RTCString(pszKey)].pszValue = pszVal; 177 } 178 179 RTMemFree(pszKey); 180 181 *puOffset += uCur - *puOffset; 182 } 183 } 184 else /* No pair detected, check for a new block. */ 185 { 186 do 187 { 188 if (*pszEnd == '\0') 189 { 190 *puOffset = uCur; 191 rc = VERR_MORE_DATA; 192 break; 193 } 194 pszEnd++; 195 } while (++uCur < cbData); 196 } 197 198 if (RT_FAILURE(rc)) 199 break; 178 200 } 201 202 RT_CLAMP(*puOffset, 0, cbData); 179 203 180 204 return rc; … … 206 230 207 231 if (sizeof("sizecheck") != 10) 208 RTTestFailed(hTest, "Basic size test failed (%u <-> 10)", sizeof("sizecheck")); 232 RTTestFailed(hTest, "Basic size test #1 failed (%u <-> 10)", sizeof("sizecheck")); 233 if (sizeof("off=rab") != 8) 234 RTTestFailed(hTest, "Basic size test #2 failed (%u <-> 7)", sizeof("off=rab")); 235 if (sizeof("off=rab\0\0") != 10) 236 RTTestFailed(hTest, "Basic size test #3 failed (%u <-> 10)", sizeof("off=rab\0\0")); 209 237 210 238 RTTestIPrintf(RTTESTLVL_INFO, "Doing line tests ...\n"); 211 239 212 for (unsigned iTest = 0; iTest < RT_ELEMENTS(aTests); iTest++) 240 unsigned iTest = 0; 241 for (iTest; iTest < RT_ELEMENTS(aTests); iTest++) 213 242 { 214 243 GuestBufferMap bufMap; 244 uint32_t uOffset = aTests[iTest].uOffsetStart; 215 245 216 246 int iResult = outputBufferParse((BYTE*)aTests[iTest].pbData, aTests[iTest].cbData, 217 & aTests[iTest].uOffsetStart, bufMap);247 &uOffset, bufMap); 218 248 219 249 RTTestIPrintf(RTTESTLVL_DEBUG, "=> Test #%u\n", iTest); … … 229 259 bufMap.size(), aTests[iTest].uMapElements); 230 260 } 231 else if ( aTests[iTest].uOffsetStart != aTests[iTest].uOffsetAfter)261 else if (uOffset != aTests[iTest].uOffsetAfter) 232 262 { 233 263 RTTestFailed(hTest, "\tOffset %u wrong, expected %u", 234 aTests[iTest].uOffsetStart, aTests[iTest].uOffsetAfter);264 uOffset, aTests[iTest].uOffsetAfter); 235 265 } 236 266 else if (iResult == VERR_MORE_DATA) 237 267 { 268 RTTestIPrintf(RTTESTLVL_DEBUG, "\tMore data (Offset: %u)\n", uOffset); 269 238 270 /* There is remaining data left in the buffer (which needs to be merged 239 271 * with a following buffer) -- print it. */ 240 const char *pszRemaining = aTests[iTest].pbData; 241 size_t uOffsetNew = aTests[iTest].uOffsetStart; 242 size_t uToWrite = aTests[iTest].cbData - uOffsetNew; 243 if (pszRemaining && uOffsetNew) 244 { 272 size_t uToWrite = aTests[iTest].cbData - uOffset; 273 if (uToWrite) 274 { 275 const char *pszRemaining = aTests[iTest].pbData; 245 276 RTTestIPrintf(RTTESTLVL_DEBUG, "\tRemaining (%u):\n", uToWrite); 246 RTStrmWriteEx(g_pStdOut, &aTests[iTest].pbData[uOffset New], uToWrite - 1, NULL);277 RTStrmWriteEx(g_pStdOut, &aTests[iTest].pbData[uOffset], uToWrite - 1, NULL); 247 278 RTTestIPrintf(RTTESTLVL_DEBUG, "\n"); 248 279 } … … 264 295 uint32_t uNumBlocks = 0; 265 296 266 while (uOffset < aTests2[iTest].cbData )297 while (uOffset < aTests2[iTest].cbData - 1) 267 298 { 268 299 iResult = outputBufferParse((BYTE*)aTests2[iTest].pbData, aTests2[iTest].cbData, … … 279 310 RTTestIPrintf(RTTESTLVL_DEBUG, "\tNext offset %u (total: %u)\n", 280 311 uOffset, aTests2[iTest].cbData); 281 uOffset++;282 312 } 283 313 else … … 288 318 } 289 319 290 if (uNumBlocks != aTests2[iTest].uNumBlocks) 320 if (iResult != aTests2[iTest].iResult) 321 { 322 RTTestFailed(hTest, "\tReturned %Rrc, expected %Rrc", 323 iResult, aTests2[iTest].iResult); 324 } 325 else if (uNumBlocks != aTests2[iTest].uNumBlocks) 291 326 { 292 327 RTTestFailed(hTest, "\tReturned %u blocks, expected %u\n",
Note:
See TracChangeset
for help on using the changeset viewer.