- Timestamp:
- Mar 5, 2018 8:30:44 PM (7 years ago)
- Location:
- trunk/src/VBox
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
r71168 r71213 298 298 kStreamTransform_Unix2Dos 299 299 }; 300 301 302 /*********************************************************************************************************************************303 * Internal Functions *304 *********************************************************************************************************************************/305 static int gctlCopyDirExists(PCOPYCONTEXT pContext, bool bGuest, const char *pszDir, bool *fExists);306 307 300 #endif /* VBOX_ONLY_DOCS */ 308 309 301 310 302 … … 1737 1729 1738 1730 1739 /** bird: This is just a code conversion tool, flags are better defined by1740 * the preprocessor, in general. But the code was using obsoleted1741 * main flags for internal purposes (in a uint32_t) without passing them1742 * along, or it seemed that way. Enum means compiler checks types. */1743 enum gctlCopyFlags1744 {1745 kGctlCopyFlags_None = 0,1746 kGctlCopyFlags_Recursive = RT_BIT(1),1747 kGctlCopyFlags_FollowLinks = RT_BIT(2)1748 };1749 1750 1751 /**1752 * Creates a copy context structure which then can be used with various1753 * guest control copy functions. Needs to be free'd with gctlCopyContextFree().1754 *1755 * @return IPRT status code.1756 * @param pCtx Pointer to command context.1757 * @param fDryRun Flag indicating if we want to run a dry run only.1758 * @param fHostToGuest Flag indicating if we want to copy from host to guest1759 * or vice versa.1760 * @param strSessionName Session name (only for identification purposes).1761 * @param ppContext Pointer which receives the allocated copy context.1762 */1763 static int gctlCopyContextCreate(PGCTLCMDCTX pCtx, bool fDryRun, bool fHostToGuest,1764 const Utf8Str &strSessionName,1765 PCOPYCONTEXT *ppContext)1766 {1767 RT_NOREF(strSessionName);1768 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);1769 1770 int vrc = VINF_SUCCESS;1771 try1772 {1773 PCOPYCONTEXT pContext = new COPYCONTEXT();1774 1775 pContext->pCmdCtx = pCtx;1776 pContext->fDryRun = fDryRun;1777 pContext->fHostToGuest = fHostToGuest;1778 1779 *ppContext = pContext;1780 }1781 catch (std::bad_alloc)1782 {1783 vrc = VERR_NO_MEMORY;1784 }1785 1786 return vrc;1787 }1788 1789 /**1790 * Frees are previously allocated copy context structure.1791 *1792 * @param pContext Pointer to copy context to free.1793 */1794 static void gctlCopyContextFree(PCOPYCONTEXT pContext)1795 {1796 if (pContext)1797 delete pContext;1798 }1799 1800 /**1801 * Translates a source path to a destination path (can be both sides,1802 * either host or guest). The source root is needed to determine the start1803 * of the relative source path which also needs to present in the destination1804 * path.1805 *1806 * @return IPRT status code.1807 * @param pszSourceRoot Source root path. No trailing directory slash!1808 * @param pszSource Actual source to transform. Must begin with1809 * the source root path!1810 * @param pszDest Destination path.1811 * @param ppszTranslated Pointer to the allocated, translated destination1812 * path. Must be free'd with RTStrFree().1813 */1814 static int gctlCopyTranslatePath(const char *pszSourceRoot, const char *pszSource,1815 const char *pszDest, char **ppszTranslated)1816 {1817 AssertPtrReturn(pszSourceRoot, VERR_INVALID_POINTER);1818 AssertPtrReturn(pszSource, VERR_INVALID_POINTER);1819 AssertPtrReturn(pszDest, VERR_INVALID_POINTER);1820 AssertPtrReturn(ppszTranslated, VERR_INVALID_POINTER);1821 #if 0 /** @todo r=bird: It does not make sense to apply host path parsing semantics onto guest paths. I hope this code isn't mixing host/guest paths in the same way anywhere else... @bugref{6344} */1822 AssertReturn(RTPathStartsWith(pszSource, pszSourceRoot), VERR_INVALID_PARAMETER);1823 #endif1824 1825 /* Construct the relative dest destination path by "subtracting" the1826 * source from the source root, e.g.1827 *1828 * source root path = "e:\foo\", source = "e:\foo\bar"1829 * dest = "d:\baz\"1830 * translated = "d:\baz\bar\"1831 */1832 char szTranslated[RTPATH_MAX];1833 size_t srcOff = strlen(pszSourceRoot);1834 AssertReturn(srcOff, VERR_INVALID_PARAMETER);1835 1836 char *pszDestPath = RTStrDup(pszDest);1837 AssertPtrReturn(pszDestPath, VERR_NO_MEMORY);1838 1839 int vrc;1840 if (!RTPathFilename(pszDestPath))1841 {1842 vrc = RTPathJoin(szTranslated, sizeof(szTranslated),1843 pszDestPath, &pszSource[srcOff]);1844 }1845 else1846 {1847 char *pszDestFileName = RTStrDup(RTPathFilename(pszDestPath));1848 if (pszDestFileName)1849 {1850 RTPathStripFilename(pszDestPath);1851 vrc = RTPathJoin(szTranslated, sizeof(szTranslated),1852 pszDestPath, pszDestFileName);1853 RTStrFree(pszDestFileName);1854 }1855 else1856 vrc = VERR_NO_MEMORY;1857 }1858 RTStrFree(pszDestPath);1859 1860 if (RT_SUCCESS(vrc))1861 {1862 *ppszTranslated = RTStrDup(szTranslated);1863 #if 01864 RTPrintf("Root: %s, Source: %s, Dest: %s, Translated: %s\n",1865 pszSourceRoot, pszSource, pszDest, *ppszTranslated);1866 #endif1867 }1868 return vrc;1869 }1870 1871 #ifdef DEBUG_andy_disabled1872 static int tstTranslatePath()1873 {1874 RTAssertSetMayPanic(false /* Do not freak out, please. */);1875 1876 static struct1877 {1878 const char *pszSourceRoot;1879 const char *pszSource;1880 const char *pszDest;1881 const char *pszTranslated;1882 int iResult;1883 } aTests[] =1884 {1885 /* Invalid stuff. */1886 { NULL, NULL, NULL, NULL, VERR_INVALID_POINTER },1887 #ifdef RT_OS_WINDOWS1888 /* Windows paths. */1889 { "c:\\foo", "c:\\foo\\bar.txt", "c:\\test", "c:\\test\\bar.txt", VINF_SUCCESS },1890 { "c:\\foo", "c:\\foo\\baz\\bar.txt", "c:\\test", "c:\\test\\baz\\bar.txt", VINF_SUCCESS },1891 #else /* RT_OS_WINDOWS */1892 { "/home/test/foo", "/home/test/foo/bar.txt", "/opt/test", "/opt/test/bar.txt", VINF_SUCCESS },1893 { "/home/test/foo", "/home/test/foo/baz/bar.txt", "/opt/test", "/opt/test/baz/bar.txt", VINF_SUCCESS },1894 #endif /* !RT_OS_WINDOWS */1895 /* Mixed paths*/1896 /** @todo */1897 { NULL }1898 };1899 1900 size_t iTest = 0;1901 for (iTest; iTest < RT_ELEMENTS(aTests); iTest++)1902 {1903 RTPrintf("=> Test %d\n", iTest);1904 RTPrintf("\tSourceRoot=%s, Source=%s, Dest=%s\n",1905 aTests[iTest].pszSourceRoot, aTests[iTest].pszSource, aTests[iTest].pszDest);1906 1907 char *pszTranslated = NULL;1908 int iResult = gctlCopyTranslatePath(aTests[iTest].pszSourceRoot, aTests[iTest].pszSource,1909 aTests[iTest].pszDest, &pszTranslated);1910 if (iResult != aTests[iTest].iResult)1911 {1912 RTPrintf("\tReturned %Rrc, expected %Rrc\n",1913 iResult, aTests[iTest].iResult);1914 }1915 else if ( pszTranslated1916 && strcmp(pszTranslated, aTests[iTest].pszTranslated))1917 {1918 RTPrintf("\tReturned translated path %s, expected %s\n",1919 pszTranslated, aTests[iTest].pszTranslated);1920 }1921 1922 if (pszTranslated)1923 {1924 RTPrintf("\tTranslated=%s\n", pszTranslated);1925 RTStrFree(pszTranslated);1926 }1927 }1928 1929 return VINF_SUCCESS; /** @todo */1930 }1931 #endif1932 1933 /**1934 * Creates a directory on the destination, based on the current copy1935 * context.1936 *1937 * @return IPRT status code.1938 * @param pContext Pointer to current copy control context.1939 * @param pszDir Directory to create.1940 */1941 static int gctlCopyDirCreate(PCOPYCONTEXT pContext, const char *pszDir)1942 {1943 AssertPtrReturn(pContext, VERR_INVALID_POINTER);1944 AssertPtrReturn(pszDir, VERR_INVALID_POINTER);1945 1946 bool fDirExists;1947 int vrc = gctlCopyDirExists(pContext, pContext->fHostToGuest, pszDir, &fDirExists);1948 if ( RT_SUCCESS(vrc)1949 && fDirExists)1950 {1951 if (pContext->pCmdCtx->cVerbose)1952 RTPrintf("Directory \"%s\" already exists\n", pszDir);1953 return VINF_SUCCESS;1954 }1955 1956 /* If querying for a directory existence fails there's no point of even trying1957 * to create such a directory. */1958 if (RT_FAILURE(vrc))1959 return vrc;1960 1961 if (pContext->pCmdCtx->cVerbose)1962 RTPrintf("Creating directory \"%s\" ...\n", pszDir);1963 1964 if (pContext->fDryRun)1965 return VINF_SUCCESS;1966 1967 if (pContext->fHostToGuest) /* We want to create directories on the guest. */1968 {1969 SafeArray<DirectoryCreateFlag_T> dirCreateFlags;1970 dirCreateFlags.push_back(DirectoryCreateFlag_Parents);1971 HRESULT rc = pContext->pCmdCtx->pGuestSession->DirectoryCreate(Bstr(pszDir).raw(),1972 0700, ComSafeArrayAsInParam(dirCreateFlags));1973 if (FAILED(rc))1974 vrc = gctlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession));1975 }1976 else /* ... or on the host. */1977 {1978 vrc = RTDirCreateFullPath(pszDir, 0700);1979 if (vrc == VERR_ALREADY_EXISTS)1980 vrc = VINF_SUCCESS;1981 }1982 return vrc;1983 }1984 1985 /**1986 * Checks whether a specific host/guest directory exists.1987 *1988 * @return IPRT status code.1989 * @param pContext Pointer to current copy control context.1990 * @param fOnGuest true if directory needs to be checked on the guest1991 * or false if on the host.1992 * @param pszDir Actual directory to check.1993 * @param fExists Pointer which receives the result if the1994 * given directory exists or not.1995 */1996 static int gctlCopyDirExists(PCOPYCONTEXT pContext, bool fOnGuest,1997 const char *pszDir, bool *fExists)1998 {1999 AssertPtrReturn(pContext, false);2000 AssertPtrReturn(pszDir, false);2001 AssertPtrReturn(fExists, false);2002 2003 int vrc = VINF_SUCCESS;2004 if (fOnGuest)2005 {2006 BOOL fDirExists = FALSE;2007 HRESULT rc = pContext->pCmdCtx->pGuestSession->DirectoryExists(Bstr(pszDir).raw(), FALSE /*followSymlinks*/, &fDirExists);2008 if (SUCCEEDED(rc))2009 *fExists = fDirExists != FALSE;2010 else2011 vrc = gctlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession));2012 }2013 else2014 *fExists = RTDirExists(pszDir);2015 return vrc;2016 }2017 2018 #if 0 /* unused */2019 /**2020 * Checks whether a specific directory exists on the destination, based2021 * on the current copy context.2022 *2023 * @return IPRT status code.2024 * @param pContext Pointer to current copy control context.2025 * @param pszDir Actual directory to check.2026 * @param fExists Pointer which receives the result if the2027 * given directory exists or not.2028 */2029 static int gctlCopyDirExistsOnDest(PCOPYCONTEXT pContext, const char *pszDir,2030 bool *fExists)2031 {2032 return gctlCopyDirExists(pContext, pContext->fHostToGuest,2033 pszDir, fExists);2034 }2035 #endif /* unused */2036 2037 /**2038 * Checks whether a specific directory exists on the source, based2039 * on the current copy context.2040 *2041 * @return IPRT status code.2042 * @param pContext Pointer to current copy control context.2043 * @param pszDir Actual directory to check.2044 * @param fExists Pointer which receives the result if the2045 * given directory exists or not.2046 */2047 static int gctlCopyDirExistsOnSource(PCOPYCONTEXT pContext, const char *pszDir,2048 bool *fExists)2049 {2050 return gctlCopyDirExists(pContext, !pContext->fHostToGuest,2051 pszDir, fExists);2052 }2053 2054 /**2055 * Checks whether a specific host/guest file exists.2056 *2057 * @return IPRT status code.2058 * @param pContext Pointer to current copy control context.2059 * @param bGuest true if file needs to be checked on the guest2060 * or false if on the host.2061 * @param pszFile Actual file to check.2062 * @param fExists Pointer which receives the result if the2063 * given file exists or not.2064 */2065 static int gctlCopyFileExists(PCOPYCONTEXT pContext, bool bOnGuest,2066 const char *pszFile, bool *fExists)2067 {2068 AssertPtrReturn(pContext, false);2069 AssertPtrReturn(pszFile, false);2070 AssertPtrReturn(fExists, false);2071 2072 int vrc = VINF_SUCCESS;2073 if (bOnGuest)2074 {2075 BOOL fFileExists = FALSE;2076 HRESULT rc = pContext->pCmdCtx->pGuestSession->FileExists(Bstr(pszFile).raw(), FALSE /*followSymlinks*/, &fFileExists);2077 if (SUCCEEDED(rc))2078 *fExists = fFileExists != FALSE;2079 else2080 vrc = gctlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession));2081 }2082 else2083 *fExists = RTFileExists(pszFile);2084 return vrc;2085 }2086 2087 #if 0 /* unused */2088 /**2089 * Checks whether a specific file exists on the destination, based on the2090 * current copy context.2091 *2092 * @return IPRT status code.2093 * @param pContext Pointer to current copy control context.2094 * @param pszFile Actual file to check.2095 * @param fExists Pointer which receives the result if the2096 * given file exists or not.2097 */2098 static int gctlCopyFileExistsOnDest(PCOPYCONTEXT pContext, const char *pszFile,2099 bool *fExists)2100 {2101 return gctlCopyFileExists(pContext, pContext->fHostToGuest,2102 pszFile, fExists);2103 }2104 #endif /* unused */2105 2106 /**2107 * Checks whether a specific file exists on the source, based on the2108 * current copy context.2109 *2110 * @return IPRT status code.2111 * @param pContext Pointer to current copy control context.2112 * @param pszFile Actual file to check.2113 * @param fExists Pointer which receives the result if the2114 * given file exists or not.2115 */2116 static int gctlCopyFileExistsOnSource(PCOPYCONTEXT pContext, const char *pszFile,2117 bool *fExists)2118 {2119 return gctlCopyFileExists(pContext, !pContext->fHostToGuest,2120 pszFile, fExists);2121 }2122 2123 /**2124 * Copies a source file to the destination.2125 *2126 * @return IPRT status code.2127 * @param pContext Pointer to current copy control context.2128 * @param pszFileSource Source file to copy to the destination.2129 * @param pszFileDest Name of copied file on the destination.2130 * @param enmFlags Copy flags. No supported at the moment and2131 * needs to be set to 0.2132 */2133 static int gctlCopyFileToDest(PCOPYCONTEXT pContext, const char *pszFileSource,2134 const char *pszFileDest, gctlCopyFlags enmFlags)2135 {2136 AssertPtrReturn(pContext, VERR_INVALID_POINTER);2137 AssertPtrReturn(pszFileSource, VERR_INVALID_POINTER);2138 AssertPtrReturn(pszFileDest, VERR_INVALID_POINTER);2139 AssertReturn(enmFlags == kGctlCopyFlags_None, VERR_INVALID_PARAMETER); /* No flags supported yet. */2140 2141 if (pContext->pCmdCtx->cVerbose)2142 RTPrintf("Copying \"%s\" to \"%s\" ...\n", pszFileSource, pszFileDest);2143 2144 if (pContext->fDryRun)2145 return VINF_SUCCESS;2146 2147 int vrc = VINF_SUCCESS;2148 ComPtr<IProgress> pProgress;2149 HRESULT rc;2150 if (pContext->fHostToGuest)2151 {2152 SafeArray<FileCopyFlag_T> copyFlags;2153 rc = pContext->pCmdCtx->pGuestSession->FileCopyToGuest(Bstr(pszFileSource).raw(), Bstr(pszFileDest).raw(),2154 ComSafeArrayAsInParam(copyFlags),2155 pProgress.asOutParam());2156 }2157 else2158 {2159 SafeArray<FileCopyFlag_T> copyFlags;2160 rc = pContext->pCmdCtx->pGuestSession->FileCopyFromGuest(Bstr(pszFileSource).raw(), Bstr(pszFileDest).raw(),2161 ComSafeArrayAsInParam(copyFlags),2162 pProgress.asOutParam());2163 }2164 2165 if (FAILED(rc))2166 {2167 vrc = gctlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession));2168 }2169 else2170 {2171 if (pContext->pCmdCtx->cVerbose)2172 rc = showProgress(pProgress);2173 else2174 rc = pProgress->WaitForCompletion(-1 /* No timeout */);2175 if (SUCCEEDED(rc))2176 CHECK_PROGRESS_ERROR(pProgress, ("File copy failed"));2177 vrc = gctlPrintProgressError(pProgress);2178 }2179 2180 return vrc;2181 }2182 2183 /**2184 * Copys a directory (tree) from host to the guest.2185 *2186 * @return IPRT status code.2187 * @param pContext Pointer to current copy control context.2188 * @param pszSource Source directory on the host to copy to the guest.2189 * @param pszFilter DOS-style wildcard filter (?, *). Optional.2190 * @param pszDest Destination directory on the guest.2191 * @param enmFlags Copy flags, such as recursive copying.2192 * @param pszSubDir Current sub directory to handle. Needs to NULL and only2193 * is needed for recursion.2194 */2195 static int gctlCopyDirToGuest(PCOPYCONTEXT pContext,2196 const char *pszSource, const char *pszFilter,2197 const char *pszDest, enum gctlCopyFlags enmFlags,2198 const char *pszSubDir /* For recursion. */)2199 {2200 AssertPtrReturn(pContext, VERR_INVALID_POINTER);2201 AssertPtrReturn(pszSource, VERR_INVALID_POINTER);2202 /* Filter is optional. */2203 AssertPtrReturn(pszDest, VERR_INVALID_POINTER);2204 /* Sub directory is optional. */2205 2206 /*2207 * Construct current path.2208 */2209 char szCurDir[RTPATH_MAX];2210 int vrc = RTStrCopy(szCurDir, sizeof(szCurDir), pszSource);2211 if (RT_SUCCESS(vrc) && pszSubDir)2212 vrc = RTPathAppend(szCurDir, sizeof(szCurDir), pszSubDir);2213 2214 if (pContext->pCmdCtx->cVerbose)2215 RTPrintf("Processing host directory: %s\n", szCurDir);2216 2217 /* Flag indicating whether the current directory was created on the2218 * target or not. */2219 bool fDirCreated = false;2220 2221 /*2222 * Open directory without a filter - RTDirOpenFiltered unfortunately2223 * cannot handle sub directories so we have to do the filtering ourselves.2224 */2225 if (RT_SUCCESS(vrc))2226 {2227 RTDIR hDir;2228 vrc = RTDirOpen(&hDir, szCurDir);2229 if (RT_SUCCESS(vrc))2230 {2231 /*2232 * Enumerate the directory tree.2233 */2234 size_t cbDirEntry = 0;2235 PRTDIRENTRYEX pDirEntry = NULL;2236 while (RT_SUCCESS(vrc))2237 {2238 vrc = RTDirReadExA(hDir, &pDirEntry, &cbDirEntry, RTFSOBJATTRADD_NOTHING, 0);2239 if (RT_FAILURE(vrc))2240 {2241 if (vrc == VERR_NO_MORE_FILES)2242 vrc = VINF_SUCCESS;2243 break;2244 }2245 2246 switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK)2247 {2248 case RTFS_TYPE_DIRECTORY:2249 {2250 /* Skip "." and ".." entries. */2251 if (RTDirEntryExIsStdDotLink(pDirEntry))2252 break;2253 2254 if (pContext->pCmdCtx->cVerbose)2255 RTPrintf("Directory: %s\n", pDirEntry->szName);2256 2257 if (enmFlags & kGctlCopyFlags_Recursive)2258 {2259 char *pszNewSub = NULL;2260 if (pszSubDir)2261 pszNewSub = RTPathJoinA(pszSubDir, pDirEntry->szName);2262 else2263 {2264 pszNewSub = RTStrDup(pDirEntry->szName);2265 RTPathStripTrailingSlash(pszNewSub);2266 }2267 2268 if (pszNewSub)2269 {2270 vrc = gctlCopyDirToGuest(pContext,2271 pszSource, pszFilter,2272 pszDest, enmFlags, pszNewSub);2273 RTStrFree(pszNewSub);2274 }2275 else2276 vrc = VERR_NO_MEMORY;2277 }2278 break;2279 }2280 2281 case RTFS_TYPE_SYMLINK:2282 if ( (enmFlags & kGctlCopyFlags_Recursive)2283 && (enmFlags & kGctlCopyFlags_FollowLinks))2284 { /* Fall through to next case is intentional. */ }2285 else2286 break;2287 RT_FALL_THRU();2288 2289 case RTFS_TYPE_FILE:2290 {2291 if ( pszFilter2292 && !RTStrSimplePatternMatch(pszFilter, pDirEntry->szName))2293 {2294 break; /* Filter does not match. */2295 }2296 2297 if (pContext->pCmdCtx->cVerbose)2298 RTPrintf("File: %s\n", pDirEntry->szName);2299 2300 if (!fDirCreated)2301 {2302 char *pszDestDir;2303 vrc = gctlCopyTranslatePath(pszSource, szCurDir, pszDest, &pszDestDir);2304 if (RT_SUCCESS(vrc))2305 {2306 vrc = gctlCopyDirCreate(pContext, pszDestDir);2307 RTStrFree(pszDestDir);2308 2309 fDirCreated = true;2310 }2311 }2312 2313 if (RT_SUCCESS(vrc))2314 {2315 char *pszFileSource = RTPathJoinA(szCurDir, pDirEntry->szName);2316 if (pszFileSource)2317 {2318 char *pszFileDest;2319 vrc = gctlCopyTranslatePath(pszSource, pszFileSource, pszDest, &pszFileDest);2320 if (RT_SUCCESS(vrc))2321 {2322 vrc = gctlCopyFileToDest(pContext, pszFileSource,2323 pszFileDest, kGctlCopyFlags_None);2324 RTStrFree(pszFileDest);2325 }2326 RTStrFree(pszFileSource);2327 }2328 }2329 break;2330 }2331 2332 default:2333 break;2334 }2335 if (RT_FAILURE(vrc))2336 break;2337 }2338 2339 RTDirReadExAFree(&pDirEntry, &cbDirEntry);2340 RTDirClose(hDir);2341 }2342 }2343 return vrc;2344 }2345 2346 /**2347 * Copys a directory (tree) from guest to the host.2348 *2349 * @return IPRT status code.2350 * @param pContext Pointer to current copy control context.2351 * @param pszSource Source directory on the guest to copy to the host.2352 * @param pszFilter DOS-style wildcard filter (?, *). Optional.2353 * @param pszDest Destination directory on the host.2354 * @param enmFlags Copy flags, such as recursive copying.2355 * @param pszSubDir Current sub directory to handle. Needs to NULL and only2356 * is needed for recursion.2357 */2358 static int gctlCopyDirToHost(PCOPYCONTEXT pContext,2359 const char *pszSource, const char *pszFilter,2360 const char *pszDest, gctlCopyFlags enmFlags,2361 const char *pszSubDir /* For recursion. */)2362 {2363 AssertPtrReturn(pContext, VERR_INVALID_POINTER);2364 AssertPtrReturn(pszSource, VERR_INVALID_POINTER);2365 /* Filter is optional. */2366 AssertPtrReturn(pszDest, VERR_INVALID_POINTER);2367 /* Sub directory is optional. */2368 2369 /*2370 * Construct current path.2371 */2372 char szCurDir[RTPATH_MAX];2373 int vrc = RTStrCopy(szCurDir, sizeof(szCurDir), pszSource);2374 if (RT_SUCCESS(vrc) && pszSubDir)2375 vrc = RTPathAppend(szCurDir, sizeof(szCurDir), pszSubDir);2376 2377 if (RT_FAILURE(vrc))2378 return vrc;2379 2380 if (pContext->pCmdCtx->cVerbose)2381 RTPrintf("Processing guest directory: %s\n", szCurDir);2382 2383 /* Flag indicating whether the current directory was created on the2384 * target or not. */2385 bool fDirCreated = false;2386 SafeArray<DirectoryOpenFlag_T> dirOpenFlags; /* No flags supported yet. */2387 ComPtr<IGuestDirectory> pDirectory;2388 HRESULT rc = pContext->pCmdCtx->pGuestSession->DirectoryOpen(Bstr(szCurDir).raw(), Bstr(pszFilter).raw(),2389 ComSafeArrayAsInParam(dirOpenFlags),2390 pDirectory.asOutParam());2391 if (FAILED(rc))2392 return gctlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession));2393 ComPtr<IFsObjInfo> dirEntry;2394 while (true)2395 {2396 rc = pDirectory->Read(dirEntry.asOutParam());2397 if (FAILED(rc))2398 break;2399 2400 FsObjType_T enmType;2401 dirEntry->COMGETTER(Type)(&enmType);2402 2403 Bstr strName;2404 dirEntry->COMGETTER(Name)(strName.asOutParam());2405 2406 switch (enmType)2407 {2408 case FsObjType_Directory:2409 {2410 Assert(!strName.isEmpty());2411 2412 /* Skip "." and ".." entries. */2413 if ( !strName.compare(Bstr("."))2414 || !strName.compare(Bstr("..")))2415 break;2416 2417 if (pContext->pCmdCtx->cVerbose)2418 {2419 Utf8Str strDir(strName);2420 RTPrintf("Directory: %s\n", strDir.c_str());2421 }2422 2423 if (enmFlags & kGctlCopyFlags_Recursive)2424 {2425 Utf8Str strDir(strName);2426 char *pszNewSub = NULL;2427 if (pszSubDir)2428 pszNewSub = RTPathJoinA(pszSubDir, strDir.c_str());2429 else2430 {2431 pszNewSub = RTStrDup(strDir.c_str());2432 RTPathStripTrailingSlash(pszNewSub);2433 }2434 if (pszNewSub)2435 {2436 vrc = gctlCopyDirToHost(pContext,2437 pszSource, pszFilter,2438 pszDest, enmFlags, pszNewSub);2439 RTStrFree(pszNewSub);2440 }2441 else2442 vrc = VERR_NO_MEMORY;2443 }2444 break;2445 }2446 2447 case FsObjType_Symlink:2448 if ( (enmFlags & kGctlCopyFlags_Recursive)2449 && (enmFlags & kGctlCopyFlags_FollowLinks))2450 {2451 /* Fall through to next case is intentional. */2452 }2453 else2454 break;2455 2456 case FsObjType_File:2457 {2458 Assert(!strName.isEmpty());2459 2460 Utf8Str strFile(strName);2461 if ( pszFilter2462 && !RTStrSimplePatternMatch(pszFilter, strFile.c_str()))2463 {2464 break; /* Filter does not match. */2465 }2466 2467 if (pContext->pCmdCtx->cVerbose)2468 RTPrintf("File: %s\n", strFile.c_str());2469 2470 if (!fDirCreated)2471 {2472 char *pszDestDir;2473 vrc = gctlCopyTranslatePath(pszSource, szCurDir,2474 pszDest, &pszDestDir);2475 if (RT_SUCCESS(vrc))2476 {2477 vrc = gctlCopyDirCreate(pContext, pszDestDir);2478 RTStrFree(pszDestDir);2479 2480 fDirCreated = true;2481 }2482 }2483 2484 if (RT_SUCCESS(vrc))2485 {2486 char *pszFileSource = RTPathJoinA(szCurDir, strFile.c_str());2487 if (pszFileSource)2488 {2489 char *pszFileDest;2490 vrc = gctlCopyTranslatePath(pszSource, pszFileSource,2491 pszDest, &pszFileDest);2492 if (RT_SUCCESS(vrc))2493 {2494 vrc = gctlCopyFileToDest(pContext, pszFileSource,2495 pszFileDest, kGctlCopyFlags_None);2496 RTStrFree(pszFileDest);2497 }2498 RTStrFree(pszFileSource);2499 }2500 else2501 vrc = VERR_NO_MEMORY;2502 }2503 break;2504 }2505 2506 default:2507 RTPrintf("Warning: Directory entry of type %ld not handled, skipping ...\n",2508 enmType);2509 break;2510 }2511 2512 if (RT_FAILURE(vrc))2513 break;2514 }2515 2516 if (RT_UNLIKELY(FAILED(rc)))2517 {2518 switch (rc)2519 {2520 case E_ABORT: /* No more directory entries left to process. */2521 break;2522 2523 case VBOX_E_FILE_ERROR: /* Current entry cannot be accessed to2524 to missing rights. */2525 {2526 RTPrintf("Warning: Cannot access \"%s\", skipping ...\n",2527 szCurDir);2528 break;2529 }2530 2531 default:2532 vrc = gctlPrintError(pDirectory, COM_IIDOF(IGuestDirectory));2533 break;2534 }2535 }2536 2537 HRESULT rc2 = pDirectory->Close();2538 if (FAILED(rc2))2539 {2540 int vrc2 = gctlPrintError(pDirectory, COM_IIDOF(IGuestDirectory));2541 if (RT_SUCCESS(vrc))2542 vrc = vrc2;2543 }2544 else if (SUCCEEDED(rc))2545 rc = rc2;2546 2547 return vrc;2548 }2549 2550 /**2551 * Copys a directory (tree) to the destination, based on the current copy2552 * context.2553 *2554 * @return IPRT status code.2555 * @param pContext Pointer to current copy control context.2556 * @param pszSource Source directory to copy to the destination.2557 * @param pszFilter DOS-style wildcard filter (?, *). Optional.2558 * @param pszDest Destination directory where to copy in the source2559 * source directory.2560 * @param enmFlags Copy flags, such as recursive copying.2561 */2562 static int gctlCopyDirToDest(PCOPYCONTEXT pContext,2563 const char *pszSource, const char *pszFilter,2564 const char *pszDest, enum gctlCopyFlags enmFlags)2565 {2566 if (pContext->fHostToGuest)2567 return gctlCopyDirToGuest(pContext, pszSource, pszFilter,2568 pszDest, enmFlags, NULL /* Sub directory, only for recursion. */);2569 return gctlCopyDirToHost(pContext, pszSource, pszFilter,2570 pszDest, enmFlags, NULL /* Sub directory, only for recursion. */);2571 }2572 2573 /**2574 * Creates a source root by stripping file names or filters of the specified source.2575 *2576 * @return IPRT status code.2577 * @param pszSource Source to create source root for.2578 * @param ppszSourceRoot Pointer that receives the allocated source root. Needs2579 * to be free'd with gctlCopyFreeSourceRoot().2580 */2581 static int gctlCopyCreateSourceRoot(const char *pszSource, char **ppszSourceRoot)2582 {2583 AssertPtrReturn(pszSource, VERR_INVALID_POINTER);2584 AssertPtrReturn(ppszSourceRoot, VERR_INVALID_POINTER);2585 2586 char *pszNewRoot = RTStrDup(pszSource);2587 if (!pszNewRoot)2588 return VERR_NO_MEMORY;2589 2590 size_t lenRoot = strlen(pszNewRoot);2591 if ( lenRoot2592 && ( pszNewRoot[lenRoot - 1] == '/'2593 || pszNewRoot[lenRoot - 1] == '\\')2594 )2595 {2596 pszNewRoot[lenRoot - 1] = '\0';2597 }2598 2599 if ( lenRoot > 12600 && ( pszNewRoot[lenRoot - 2] == '/'2601 || pszNewRoot[lenRoot - 2] == '\\')2602 )2603 {2604 pszNewRoot[lenRoot - 2] = '\0';2605 }2606 2607 if (!lenRoot)2608 {2609 /* If there's anything (like a file name or a filter),2610 * strip it! */2611 RTPathStripFilename(pszNewRoot);2612 }2613 2614 *ppszSourceRoot = pszNewRoot;2615 2616 return VINF_SUCCESS;2617 }2618 2619 /**2620 * Frees a previously allocated source root.2621 *2622 * @return IPRT status code.2623 * @param pszSourceRoot Source root to free.2624 */2625 static void gctlCopyFreeSourceRoot(char *pszSourceRoot)2626 {2627 RTStrFree(pszSourceRoot);2628 }2629 2630 1731 static RTEXITCODE gctlHandleCopy(PGCTLCMDCTX pCtx, int argc, char **argv, bool fHostToGuest) 2631 1732 { … … 2668 1769 Utf8Str strSource; 2669 1770 const char *pszDst = NULL; 2670 enum gctlCopyFlags enmFlags = kGctlCopyFlags_None;2671 /*bool fCopyRecursive = false; - unused */2672 1771 bool fDryRun = false; 1772 bool fFollow = false; 1773 bool fRecursive = false; 2673 1774 uint32_t uUsage = fHostToGuest ? USAGE_GSTCTRL_COPYTO : USAGE_GSTCTRL_COPYFROM; 2674 1775 … … 2688 1789 2689 1790 case GETOPTDEF_COPY_FOLLOW: 2690 enmFlags = (enum gctlCopyFlags)((uint32_t)enmFlags | kGctlCopyFlags_FollowLinks);1791 fFollow = true; 2691 1792 break; 2692 1793 2693 1794 case 'R': /* Recursive processing */ 2694 enmFlags = (enum gctlCopyFlags)((uint32_t)enmFlags | kGctlCopyFlags_Recursive);1795 fRecursive = true; 2695 1796 break; 2696 1797 … … 2747 1848 } 2748 1849 2749 /* Create the copy context -- it contains all information 2750 * the routines need to know when handling the actual copying. */ 2751 PCOPYCONTEXT pContext = NULL; 2752 vrc = gctlCopyContextCreate(pCtx, fDryRun, fHostToGuest, 2753 fHostToGuest 2754 ? "VBoxManage Guest Control - Copy to guest" 2755 : "VBoxManage Guest Control - Copy from guest", &pContext); 2756 if (RT_FAILURE(vrc)) 2757 { 2758 RTMsgError("Unable to create copy context, rc=%Rrc\n", vrc); 2759 return RTEXITCODE_FAILURE; 2760 } 2761 2762 /** @todo r=bird: RTPathFilename and RTPathStripFilename won't work 2763 * correctly on non-windows hosts when the guest is from the DOS world (Windows, 2764 * OS/2, DOS). The host doesn't know about DOS slashes, only UNIX slashes and 2765 * will get the wrong idea if some dilligent user does: 2766 * 2767 * copyto myfile.txt 'C:\guestfile.txt' 2768 * or 2769 * copyto myfile.txt 'D:guestfile.txt' 2770 * 2771 * @bugref{6344} 2772 */ 2773 if (!RTPathFilename(pszDst)) 2774 { 2775 vrc = gctlCopyDirCreate(pContext, pszDst); 1850 ComPtr<IProgress> pProgress; 1851 HRESULT rc; 1852 1853 for (unsigned long s = 0; s < vecSources.size(); s++) 1854 { 1855 char *pszSrc = RTStrDup(vecSources[s].GetSource()); 1856 AssertPtrBreakStmt(pszSrc, vrc = VERR_NO_MEMORY); 1857 const char *pszFilter = vecSources[s].GetFilter(); 1858 RT_NOREF(pszFilter); 1859 /* pszFilter can be NULL if not set. */ 1860 1861 if (fHostToGuest) 1862 { 1863 if (RTFileExists(pszSrc)) 1864 { 1865 SafeArray<FileCopyFlag_T> copyFlags; 1866 rc = pCtx->pGuestSession->FileCopyToGuest(Bstr(pszSrc).raw(), Bstr(pszDst).raw(), 1867 ComSafeArrayAsInParam(copyFlags), pProgress.asOutParam()); 1868 } 1869 else if (RTDirExists(pszSrc)) 1870 { 1871 SafeArray<DirectoryCopyFlags_T> copyFlags; 1872 copyFlags.push_back(DirectoryCopyFlags_CopyIntoExisting); 1873 rc = pCtx->pGuestSession->DirectoryCopyToGuest(Bstr(pszSrc).raw(), Bstr(pszDst).raw(), 1874 ComSafeArrayAsInParam(copyFlags), pProgress.asOutParam()); 1875 } 1876 else if (pCtx->cVerbose) 1877 RTPrintf("Warning: \"%s\" does not exist or is not a file/directory, skipping ...\n", pszSrc); 1878 } 1879 else 1880 { 1881 SafeArray<FileCopyFlag_T> copyFlags; 1882 rc = pCtx->pGuestSession->FileCopyFromGuest(Bstr(pszSrc).raw(), Bstr(pszDst).raw(), 1883 ComSafeArrayAsInParam(copyFlags), pProgress.asOutParam()); 1884 } 1885 } 1886 1887 if (FAILED(rc)) 1888 { 1889 vrc = gctlPrintError(pCtx->pGuestSession, COM_IIDOF(IGuestSession)); 2776 1890 } 2777 1891 else 2778 1892 { 2779 /* We assume we got a file name as destination -- so strip 2780 * the actual file name and make sure the appropriate 2781 * directories get created. */ 2782 char *pszDstDir = RTStrDup(pszDst); 2783 AssertPtr(pszDstDir); 2784 RTPathStripFilename(pszDstDir); 2785 vrc = gctlCopyDirCreate(pContext, pszDstDir); 2786 RTStrFree(pszDstDir); 2787 } 2788 2789 if (RT_SUCCESS(vrc)) 2790 { 2791 /* 2792 * Here starts the actual fun! 2793 * Handle all given sources one by one. 2794 */ 2795 for (unsigned long s = 0; s < vecSources.size(); s++) 2796 { 2797 char *pszSource = RTStrDup(vecSources[s].GetSource()); 2798 AssertPtrBreakStmt(pszSource, vrc = VERR_NO_MEMORY); 2799 const char *pszFilter = vecSources[s].GetFilter(); 2800 if (!strlen(pszFilter)) 2801 pszFilter = NULL; /* If empty filter then there's no filter :-) */ 2802 2803 char *pszSourceRoot; 2804 vrc = gctlCopyCreateSourceRoot(pszSource, &pszSourceRoot); 2805 if (RT_FAILURE(vrc)) 2806 { 2807 RTMsgError("Unable to create source root, rc=%Rrc\n", vrc); 2808 break; 2809 } 2810 2811 if (pCtx->cVerbose) 2812 RTPrintf("Source: %s\n", pszSource); 2813 2814 /** @todo Files with filter?? */ 2815 bool fSourceIsFile = false; 2816 bool fSourceExists; 2817 2818 size_t cchSource = strlen(pszSource); 2819 if ( cchSource > 1 2820 && RTPATH_IS_SLASH(pszSource[cchSource - 1])) 2821 { 2822 if (pszFilter) /* Directory with filter (so use source root w/o the actual filter). */ 2823 vrc = gctlCopyDirExistsOnSource(pContext, pszSourceRoot, &fSourceExists); 2824 else /* Regular directory without filter. */ 2825 vrc = gctlCopyDirExistsOnSource(pContext, pszSource, &fSourceExists); 2826 2827 if (fSourceExists) 2828 { 2829 /* Strip trailing slash from our source element so that other functions 2830 * can use this stuff properly (like RTPathStartsWith). */ 2831 RTPathStripTrailingSlash(pszSource); 2832 } 2833 } 2834 else 2835 { 2836 vrc = gctlCopyFileExistsOnSource(pContext, pszSource, &fSourceExists); 2837 if ( RT_SUCCESS(vrc) 2838 && fSourceExists) 2839 { 2840 fSourceIsFile = true; 2841 } 2842 } 2843 2844 if ( RT_SUCCESS(vrc) 2845 && fSourceExists) 2846 { 2847 if (fSourceIsFile) 2848 { 2849 /* Single file. */ 2850 char *pszDstFile; 2851 vrc = gctlCopyTranslatePath(pszSourceRoot, pszSource, pszDst, &pszDstFile); 2852 if (RT_SUCCESS(vrc)) 2853 { 2854 vrc = gctlCopyFileToDest(pContext, pszSource, pszDstFile, kGctlCopyFlags_None); 2855 RTStrFree(pszDstFile); 2856 } 2857 else 2858 RTMsgError("Unable to translate path for \"%s\", rc=%Rrc\n", pszSource, vrc); 2859 } 2860 else 2861 { 2862 /* Directory (with filter?). */ 2863 vrc = gctlCopyDirToDest(pContext, pszSource, pszFilter, pszDst, enmFlags); 2864 } 2865 } 2866 2867 gctlCopyFreeSourceRoot(pszSourceRoot); 2868 2869 if ( RT_SUCCESS(vrc) 2870 && !fSourceExists) 2871 { 2872 RTMsgError("Warning: Source \"%s\" does not exist, skipping!\n", 2873 pszSource); 2874 RTStrFree(pszSource); 2875 continue; 2876 } 2877 else if (RT_FAILURE(vrc)) 2878 { 2879 RTMsgError("Error processing \"%s\", rc=%Rrc\n", 2880 pszSource, vrc); 2881 RTStrFree(pszSource); 2882 break; 2883 } 2884 2885 RTStrFree(pszSource); 2886 } 2887 } 2888 2889 gctlCopyContextFree(pContext); 1893 if (pCtx->cVerbose) 1894 rc = showProgress(pProgress); 1895 else 1896 rc = pProgress->WaitForCompletion(-1 /* No timeout */); 1897 if (SUCCEEDED(rc)) 1898 CHECK_PROGRESS_ERROR(pProgress, ("File copy failed")); 1899 vrc = gctlPrintProgressError(pProgress); 1900 } 2890 1901 2891 1902 return RT_SUCCESS(vrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; -
trunk/src/VBox/Main/include/GuestSessionImpl.h
r69500 r71213 5 5 6 6 /* 7 * Copyright (C) 2012-201 7Oracle Corporation7 * Copyright (C) 2012-2018 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 70 70 } 71 71 72 const ComObjPtr<Progress>& GetProgressObject() const {return mProgress;} 73 74 protected: 75 76 int getGuestProperty(const ComObjPtr<Guest> &pGuest, 77 const Utf8Str &strPath, Utf8Str &strValue); 72 const ComObjPtr<Progress>& GetProgressObject() const { return mProgress; } 73 74 protected: 75 76 /** @name Directory handling primitives. 77 * @{ */ 78 int directoryCreate(const com::Utf8Str &strPath, DirectoryCreateFlag_T enmDirecotryCreateFlags, uint32_t uMode, bool fFollowSymlinks); 79 /** @} */ 80 81 /** @name File handling primitives. 82 * @{ */ 83 int fileCopyToGuestEx(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags, PRTFILE pFile, uint64_t cbOffset, uint64_t cbSize); 84 int fileCopyToGuest(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags); 85 /** @} */ 86 87 /** @name Guest property handling primitives. 88 * @{ */ 89 int getGuestProperty(const ComObjPtr<Guest> &pGuest, const Utf8Str &strPath, Utf8Str &strValue); 90 /** @} */ 91 92 /** @name Path handling primitives. 93 * @{ */ 94 int pathConstructOnGuest(const Utf8Str &strSourceRoot, const Utf8Str &strSource, const Utf8Str &strDest, Utf8Str &strOut); 95 /** @} */ 96 78 97 int setProgress(ULONG uPercent); 79 98 int setProgressSuccess(void); 80 99 HRESULT setProgressErrorMsg(HRESULT hr, const Utf8Str &strMsg); 100 81 101 inline void setTaskDesc(const Utf8Str &strTaskDesc) throw() 82 102 { … … 85 105 86 106 HRESULT createAndSetProgressObject(); 107 87 108 protected: 88 109 89 110 Utf8Str mDesc; 90 GuestSession *mSession; 111 /** The guest session object this task is working on. */ 112 ComObjPtr<GuestSession> mSession; 91 113 /** Progress object for getting updated when running 92 114 * asynchronously. Optional. */ … … 116 138 117 139 /** 140 * Task for copying directories from guest to the host. 141 */ 142 class SessionTaskCopyDirFrom : public GuestSessionTask 143 { 144 public: 145 146 SessionTaskCopyDirFrom(GuestSession *pSession, 147 const Utf8Str &strSource, const Utf8Str &strDest, const Utf8Str &strFilter, DirectoryCopyFlags_T enmDirCopyFlags); 148 virtual ~SessionTaskCopyDirFrom(void); 149 int Run(void); 150 151 protected: 152 153 int directoryCopyToHost(const Utf8Str &strSource, const Utf8Str &strFilter, const Utf8Str &strDest, bool fRecursive, bool fFollowSymlinks, 154 const Utf8Str &strSubDir /* For recursion. */); 155 protected: 156 157 Utf8Str mSource; 158 Utf8Str mDest; 159 Utf8Str mFilter; 160 DirectoryCopyFlags_T mDirCopyFlags; 161 }; 162 163 /** 164 * Task for copying directories from host to the guest. 165 */ 166 class SessionTaskCopyDirTo : public GuestSessionTask 167 { 168 public: 169 170 SessionTaskCopyDirTo(GuestSession *pSession, 171 const Utf8Str &strSource, const Utf8Str &strDest, const Utf8Str &strFilter, DirectoryCopyFlags_T enmDirCopyFlags); 172 virtual ~SessionTaskCopyDirTo(void); 173 int Run(void); 174 175 protected: 176 177 int directoryCopyToGuest(const Utf8Str &strSource, const Utf8Str &strFilter, const Utf8Str &strDest, bool fRecursive, bool fFollowSymlinks, 178 const Utf8Str &strSubDir /* For recursion. */); 179 protected: 180 181 Utf8Str mSource; 182 Utf8Str mDest; 183 Utf8Str mFilter; 184 DirectoryCopyFlags_T mDirCopyFlags; 185 }; 186 187 /** 118 188 * Task for copying files from host to the guest. 119 189 */ 120 class SessionTaskCopy To : public GuestSessionTask121 { 122 public: 123 124 SessionTaskCopy To(GuestSession *pSession,125 const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags);126 SessionTaskCopy To(GuestSession *pSession,127 PRTFILE pSourceFile, size_t cbSourceOffset, uint64_t cbSourceSize,128 const Utf8Str &strDest, uint32_t uFlags);129 virtual ~SessionTaskCopy To(void);190 class SessionTaskCopyFileTo : public GuestSessionTask 191 { 192 public: 193 194 SessionTaskCopyFileTo(GuestSession *pSession, 195 const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags); 196 SessionTaskCopyFileTo(GuestSession *pSession, 197 PRTFILE pSourceFile, size_t cbSourceOffset, uint64_t cbSourceSize, 198 const Utf8Str &strDest, uint32_t uFlags); 199 virtual ~SessionTaskCopyFileTo(void); 130 200 int Run(void); 131 201 … … 143 213 * Task for copying files from guest to the host. 144 214 */ 145 class SessionTaskCopyF rom : public GuestSessionTask146 { 147 public: 148 149 SessionTaskCopyF rom(GuestSession *pSession,215 class SessionTaskCopyFileFrom : public GuestSessionTask 216 { 217 public: 218 219 SessionTaskCopyFileFrom(GuestSession *pSession, 150 220 const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags); 151 virtual ~SessionTaskCopyF rom(void);221 virtual ~SessionTaskCopyFileFrom(void); 152 222 int Run(void); 153 223 … … 223 293 }; 224 294 225 int i_addProcessArguments(ProcessArguments &aArgumentsDest, 226 const ProcessArguments &aArgumentsSource); 227 int i_copyFileToGuest(GuestSession *pSession, PRTISOFSFILE pISO, 228 Utf8Str const &strFileSource, const Utf8Str &strFileDest, 229 bool fOptional, uint32_t *pcbSize); 230 int i_runFileOnGuest(GuestSession *pSession, GuestProcessStartupInfo &procInfo); 295 int addProcessArguments(ProcessArguments &aArgumentsDest, const ProcessArguments &aArgumentsSource); 296 int copyFileToGuest(GuestSession *pSession, PRTISOFSFILE pISO, Utf8Str const &strFileSource, const Utf8Str &strFileDest, bool fOptional, uint32_t *pcbSize); 297 int runFileOnGuest(GuestSession *pSession, GuestProcessStartupInfo &procInfo); 231 298 232 299 /** Files to handle. */ … … 423 490 * @todo r=bird: Most of these are public for no real reason... 424 491 * @{ */ 492 int i_copyToGuestCreateDir(const com::Utf8Str &aDestination, uint32_t fFlags, int *pGuestRc); 425 493 int i_closeSession(uint32_t uFlags, uint32_t uTimeoutMS, int *pGuestRc); 426 494 inline bool i_directoryExists(uint32_t uDirID, ComObjPtr<GuestDirectory> *pDir); -
trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp
r69500 r71213 5 5 6 6 /* 7 * Copyright (C) 2012-201 7Oracle Corporation7 * Copyright (C) 2012-2018 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 20 20 * Header Files * 21 21 *********************************************************************************************************************************/ 22 #define LOG_GROUP LOG_GROUP_ GUEST_CONTROL //LOG_GROUP_MAIN_GUESTSESSION22 #define LOG_GROUP LOG_GROUP_MAIN_GUESTSESSION 23 23 #include "LoggingNew.h" 24 24 … … 2457 2457 fFlags |= aFlags[i]; 2458 2458 } 2459 /** @todo r=bird: fend off flags we don't implement here! */ 2459 2460 if (fFlags) 2461 return setError(E_NOTIMPL, tr("Flag(s) not yet implemented")); 2460 2462 2461 2463 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); … … 2465 2467 try 2466 2468 { 2467 SessionTaskCopyF rom *pTask = NULL;2469 SessionTaskCopyFileFrom *pTask = NULL; 2468 2470 ComObjPtr<Progress> pProgress; 2469 2471 try 2470 2472 { 2471 pTask = new SessionTaskCopyF rom(this /* GuestSession */, aSource, aDest, fFlags);2473 pTask = new SessionTaskCopyFileFrom(this /* GuestSession */, aSource, aDest, fFlags); 2472 2474 } 2473 2475 catch(...) 2474 2476 { 2475 hr = setError(VBOX_E_IPRT_ERROR, tr("Failed to create SessionTaskCopyF rom object"));2477 hr = setError(VBOX_E_IPRT_ERROR, tr("Failed to create SessionTaskCopyFileFrom object")); 2476 2478 throw; 2477 2479 } … … 2483 2485 delete pTask; 2484 2486 hr = setError(VBOX_E_IPRT_ERROR, 2485 tr("Creating progress object for SessionTaskCopyF rom object failed"));2487 tr("Creating progress object for SessionTaskCopyFileFrom object failed")); 2486 2488 throw hr; 2487 2489 } … … 2530 2532 fFlags |= aFlags[i]; 2531 2533 } 2532 /** @todo r=bird: fend off flags we don't implement here! */ 2534 2535 if (fFlags) 2536 return setError(E_NOTIMPL, tr("Flag(s) not yet implemented")); 2533 2537 2534 2538 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); … … 2538 2542 try 2539 2543 { 2540 SessionTaskCopy To *pTask = NULL;2544 SessionTaskCopyFileTo *pTask = NULL; 2541 2545 ComObjPtr<Progress> pProgress; 2542 2546 try 2543 2547 { 2544 pTask = new SessionTaskCopy To(this /* GuestSession */, aSource, aDest, fFlags);2548 pTask = new SessionTaskCopyFileTo(this /* GuestSession */, aSource, aDest, fFlags); 2545 2549 } 2546 2550 catch(...) 2547 2551 { 2548 hr = setError(VBOX_E_IPRT_ERROR, tr("Failed to create SessionTaskCopy To object"));2552 hr = setError(VBOX_E_IPRT_ERROR, tr("Failed to create SessionTaskCopyFileTo object")); 2549 2553 throw; 2550 2554 } 2551 2552 2555 2553 2556 hr = pTask->Init(Utf8StrFmt(tr("Copying \"%s\" from host to \"%s\" on the guest"), aSource.c_str(), aDest.c_str())); … … 2556 2559 delete pTask; 2557 2560 hr = setError(VBOX_E_IPRT_ERROR, 2558 tr("Creating progress object for SessionTaskCopy To object failed"));2561 tr("Creating progress object for SessionTaskCopyFileTo object failed")); 2559 2562 throw hr; 2560 2563 } … … 2603 2606 const std::vector<DirectoryCopyFlags_T> &aFlags, ComPtr<IProgress> &aProgress) 2604 2607 { 2605 RT_NOREF(aSource, aDestination, aFlags, aProgress); 2606 ReturnComNotImplemented(); 2608 LogFlowThisFuncEnter(); 2609 2610 if (RT_UNLIKELY((aSource.c_str()) == NULL || *(aSource.c_str()) == '\0')) 2611 return setError(E_INVALIDARG, tr("No source directory specified")); 2612 2613 if (RT_UNLIKELY((aDestination.c_str()) == NULL || *(aDestination.c_str()) == '\0')) 2614 return setError(E_INVALIDARG, tr("No destination directory specified")); 2615 2616 if (!RTPathExists(aSource.c_str())) 2617 return setError(E_INVALIDARG, tr("Source directory \"%s\" does not exist"), aSource.c_str()); 2618 2619 uint32_t fFlags = DirectoryCopyFlags_None; 2620 if (aFlags.size()) 2621 { 2622 for (size_t i = 0; i < aFlags.size(); i++) 2623 fFlags |= aFlags[i]; 2624 } 2625 /** @todo Validate flags. */ 2626 2627 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 2628 2629 HRESULT hr = S_OK; 2630 2631 try 2632 { 2633 SessionTaskCopyDirTo *pTask = NULL; 2634 ComObjPtr<Progress> pProgress; 2635 try 2636 { 2637 pTask = new SessionTaskCopyDirTo(this /* GuestSession */, aSource, aDestination, "" /* strFilter */, fFlags); 2638 } 2639 catch(...) 2640 { 2641 hr = setError(VBOX_E_IPRT_ERROR, tr("Failed to create SessionTaskCopyDirTo object")); 2642 throw; 2643 } 2644 2645 hr = pTask->Init(Utf8StrFmt(tr("Copying directory \"%s\" from host to \"%s\" on the guest"), 2646 aSource.c_str(), aDestination.c_str())); 2647 if (FAILED(hr)) 2648 { 2649 delete pTask; 2650 hr = setError(VBOX_E_IPRT_ERROR, 2651 tr("Creating progress object for SessionTaskCopyDirTo object failed")); 2652 throw hr; 2653 } 2654 2655 hr = pTask->createThreadWithType(RTTHREADTYPE_MAIN_HEAVY_WORKER); 2656 2657 if (SUCCEEDED(hr)) 2658 { 2659 /* Return progress to the caller. */ 2660 pProgress = pTask->GetProgressObject(); 2661 hr = pProgress.queryInterfaceTo(aProgress.asOutParam()); 2662 } 2663 else 2664 hr = setError(VBOX_E_IPRT_ERROR, 2665 tr("Starting thread for copying directory \"%s\" from host to \"%s\" on the guest failed"), 2666 aSource.c_str(), aDestination.c_str()); 2667 } 2668 catch(std::bad_alloc &) 2669 { 2670 hr = E_OUTOFMEMORY; 2671 } 2672 catch(HRESULT eHR) 2673 { 2674 hr = eHR; 2675 LogFlowThisFunc(("Exception was caught in the function\n")); 2676 } 2677 2678 return hr; 2607 2679 } 2608 2680 … … 2706 2778 else 2707 2779 { 2708 /** @todo r=bird: Looks like this code raises errors if the directory doesn't2709 * exist... That's of course not right. */2710 2780 switch (rc) 2711 2781 { 2712 2782 case VERR_GSTCTL_GUEST_ERROR: 2713 hr = GuestProcess::i_setErrorExternal(this, guestRc); 2783 { 2784 switch (guestRc) 2785 { 2786 case VERR_PATH_NOT_FOUND: 2787 *aExists = FALSE; 2788 break; 2789 default: 2790 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory existence \"%s\" failed: %s"), 2791 aPath.c_str(), GuestProcess::i_guestErrorToString(guestRc).c_str()); 2792 break; 2793 } 2714 2794 break; 2795 } 2715 2796 2716 2797 default: -
trunk/src/VBox/Main/src-client/GuestSessionImplTasks.cpp
r69500 r71213 5 5 6 6 /* 7 * Copyright (C) 2012-201 7Oracle Corporation7 * Copyright (C) 2012-2018 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 20 20 * Header Files * 21 21 *********************************************************************************************************************************/ 22 #define LOG_GROUP LOG_GROUP_ GUEST_CONTROL //LOG_GROUP_MAIN_GUESTSESSION22 #define LOG_GROUP LOG_GROUP_MAIN_GUESTSESSION 23 23 #include "LoggingNew.h" 24 24 … … 199 199 } 200 200 201 SessionTaskOpen::SessionTaskOpen(GuestSession *pSession, 202 uint32_t uFlags, 203 uint32_t uTimeoutMS) 204 : GuestSessionTask(pSession), 205 mFlags(uFlags), 206 mTimeoutMS(uTimeoutMS) 207 { 208 m_strTaskName = "gctlSesOpen"; 209 } 210 211 SessionTaskOpen::~SessionTaskOpen(void) 212 { 213 214 } 215 216 int SessionTaskOpen::Run(void) 217 { 218 LogFlowThisFuncEnter(); 219 220 ComObjPtr<GuestSession> pSession = mSession; 221 Assert(!pSession.isNull()); 222 223 AutoCaller autoCaller(pSession); 224 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 225 226 int vrc = pSession->i_startSessionInternal(NULL /*pvrcGuest*/); 227 /* Nothing to do here anymore. */ 228 229 LogFlowFuncLeaveRC(vrc); 230 return vrc; 231 } 232 233 SessionTaskCopyTo::SessionTaskCopyTo(GuestSession *pSession, 234 const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags) 235 : GuestSessionTask(pSession), 236 mSource(strSource), 237 mSourceFile(NULL), 238 mSourceOffset(0), 239 mSourceSize(0), 240 mDest(strDest) 241 { 242 mCopyFileFlags = uFlags; 243 m_strTaskName = "gctlCpyTo"; 244 } 245 246 /** @todo Merge this and the above call and let the above call do the open/close file handling so that the 247 * inner code only has to deal with file handles. No time now ... */ 248 SessionTaskCopyTo::SessionTaskCopyTo(GuestSession *pSession, 249 PRTFILE pSourceFile, size_t cbSourceOffset, uint64_t cbSourceSize, 250 const Utf8Str &strDest, uint32_t uFlags) 251 : GuestSessionTask(pSession) 252 { 253 mSourceFile = pSourceFile; 254 mSourceOffset = cbSourceOffset; 255 mSourceSize = cbSourceSize; 256 mDest = strDest; 257 mCopyFileFlags = uFlags; 258 m_strTaskName = "gctlCpyTo"; 259 } 260 261 SessionTaskCopyTo::~SessionTaskCopyTo(void) 262 { 263 264 } 265 266 int SessionTaskCopyTo::Run(void) 267 { 268 LogFlowThisFuncEnter(); 269 270 ComObjPtr<GuestSession> pSession = mSession; 271 Assert(!pSession.isNull()); 272 273 AutoCaller autoCaller(pSession); 274 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 275 276 if (mCopyFileFlags) 277 { 278 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 279 Utf8StrFmt(GuestSession::tr("Copy flags (%#x) not implemented yet"), 280 mCopyFileFlags)); 281 return VERR_INVALID_PARAMETER; 282 } 283 284 int rc; 201 /** 202 * Creates a directory on the guest. 203 * 204 * @return VBox status code. VWRN_ALREADY_EXISTS if directory on the guest already exists. 205 * @param strPath Absolute path to directory on the guest (guest style path) to create. 206 * @param enmDirecotryCreateFlags Directory creation flags. 207 * @param uMode Directory mode to use for creation. 208 * @param fFollowSymlinks Whether to follow symlinks on the guest or not. 209 */ 210 int GuestSessionTask::directoryCreate(const com::Utf8Str &strPath, 211 DirectoryCreateFlag_T enmDirecotryCreateFlags, uint32_t uMode, bool fFollowSymlinks) 212 { 213 LogFlowFunc(("strPath=%s, fFlags=0x%x, uMode=%RU32, fFollowSymlinks=%RTbool\n", 214 strPath.c_str(), enmDirecotryCreateFlags, uMode, fFollowSymlinks)); 215 216 GuestFsObjData objData; int guestRc; 217 218 int rc = mSession->i_directoryQueryInfoInternal(strPath, fFollowSymlinks, objData, &guestRc); 219 if (RT_SUCCESS(rc)) 220 { 221 return VWRN_ALREADY_EXISTS; 222 } 223 else 224 { 225 switch (rc) 226 { 227 case VERR_GSTCTL_GUEST_ERROR: 228 { 229 switch (guestRc) 230 { 231 case VERR_FILE_NOT_FOUND: 232 case VERR_PATH_NOT_FOUND: 233 rc = mSession->i_directoryCreateInternal(strPath.c_str(), uMode, enmDirecotryCreateFlags, &guestRc); 234 break; 235 default: 236 break; 237 } 238 break; 239 } 240 241 default: 242 break; 243 } 244 } 245 246 if (RT_FAILURE(rc)) 247 { 248 if (rc == VERR_GSTCTL_GUEST_ERROR) 249 { 250 setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::i_guestErrorToString(guestRc)); 251 } 252 else 253 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 254 Utf8StrFmt(GuestSession::tr("Error creating directory on the guest: %Rrc"), strPath.c_str(), rc)); 255 } 256 257 LogFlowFuncLeaveRC(rc); 258 return rc; 259 } 260 261 /** 262 * Copies a file from the host to the guest, extended version. 263 * 264 * @return VBox status code. 265 * @param strSource Full path of source file on the host to copy. 266 * @param strDest Full destination path and file name (guest style) to copy file to. 267 * @param enmFileCopyFlags File copy flags. 268 * @param pFile Source file handle to use for accessing the host file. 269 * The caller is responsible of opening / closing the file accordingly. 270 * @param cbOffset Offset (in bytes) where to start copying the source file. 271 * @param cbSize Size (in bytes) to copy from the source file. 272 */ 273 int GuestSessionTask::fileCopyToGuestEx(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags, 274 PRTFILE pFile, uint64_t cbOffset, uint64_t cbSize) 275 { 276 /** @todo Implement sparse file support? */ 277 278 if ( enmFileCopyFlags & FileCopyFlag_NoReplace 279 || enmFileCopyFlags & FileCopyFlag_FollowLinks 280 || enmFileCopyFlags & FileCopyFlag_Update) 281 { 282 return VERR_NOT_IMPLEMENTED; 283 } 285 284 286 285 RTMSINTERVAL msTimeout = 30 * 1000; /** @todo 30s timeout for all actions. Make this configurable? */ 287 288 RTFILE fileLocal;289 PRTFILE pFile = &fileLocal;290 291 if (!mSourceFile)292 {293 /* Does our source file exist? */294 if (!RTFileExists(mSource.c_str()))295 {296 rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,297 Utf8StrFmt(GuestSession::tr("Source file \"%s\" does not exist or is not a file"),298 mSource.c_str()));299 }300 else301 {302 rc = RTFileOpen(pFile, mSource.c_str(),303 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);304 if (RT_FAILURE(rc))305 {306 rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,307 Utf8StrFmt(GuestSession::tr("Could not open source file \"%s\" for reading: %Rrc"),308 mSource.c_str(), rc));309 }310 else311 {312 rc = RTFileGetSize(*pFile, &mSourceSize);313 if (RT_FAILURE(rc))314 {315 setProgressErrorMsg(VBOX_E_IPRT_ERROR,316 Utf8StrFmt(GuestSession::tr("Could not query file size of \"%s\": %Rrc"),317 mSource.c_str(), rc));318 }319 }320 }321 }322 else323 {324 rc = VINF_SUCCESS;325 pFile = mSourceFile;326 /* Size + offset are optional. */327 }328 329 /*330 * Query information about our destination first.331 */332 int guestRc = VERR_IPE_UNINITIALIZED_STATUS;333 if (RT_SUCCESS(rc))334 {335 GuestFsObjData objData;336 rc = pSession->i_directoryQueryInfoInternal(mDest, true /* fFollowSymlinks */, objData, &guestRc);337 if (RT_SUCCESS(rc))338 {339 mDest = Utf8StrFmt("%s/%s", mDest.c_str(), RTPathFilename(mSource.c_str()));340 }341 else if (rc == VERR_NOT_A_DIRECTORY)342 {343 rc = VINF_SUCCESS;344 }345 }346 347 /** @todo Implement sparse file support? */348 286 349 287 /* … … 356 294 357 295 /* Set arguments.*/ 358 procInfo.mArguments.push_back(procInfo.mExecutable); /* Set argv0. */359 procInfo.mArguments.push_back(Utf8StrFmt("--output=%s", mDest.c_str())); /** @todo Do we need path conversion? */296 procInfo.mArguments.push_back(procInfo.mExecutable); /* Set argv0. */ 297 procInfo.mArguments.push_back(Utf8StrFmt("--output=%s", strDest.c_str())); 360 298 361 299 /* Startup process. */ 362 300 ComObjPtr<GuestProcess> pProcess; 363 if (RT_SUCCESS(rc)) 364 rc = pSession->i_processCreateExInternal(procInfo, pProcess); 301 int rc = mSession->i_processCreateExInternal(procInfo, pProcess); 302 303 int guestRc; 365 304 if (RT_SUCCESS(rc)) 366 305 { … … 382 321 Utf8StrFmt(GuestSession::tr( 383 322 "Error while creating guest process for copying file \"%s\" from guest to host: %Rrc"), 384 mSource.c_str(), rc));323 strSource.c_str(), rc)); 385 324 break; 386 325 } 387 326 } 388 327 328 if (RT_FAILURE(rc)) 329 return rc; 330 331 ProcessWaitResult_T waitRes; 332 BYTE byBuf[_64K]; 333 334 BOOL fCanceled = FALSE; 335 uint64_t cbWrittenTotal = 0; 336 uint64_t cbToRead = cbSize; 337 338 for (;;) 339 { 340 rc = pProcess->i_waitFor(ProcessWaitForFlag_StdIn, msTimeout, waitRes, &guestRc); 341 if ( RT_FAILURE(rc) 342 || ( waitRes != ProcessWaitResult_StdIn 343 && waitRes != ProcessWaitResult_WaitFlagNotSupported)) 344 { 345 break; 346 } 347 348 /* If the guest does not support waiting for stdin, we now yield in 349 * order to reduce the CPU load due to busy waiting. */ 350 if (waitRes == ProcessWaitResult_WaitFlagNotSupported) 351 RTThreadYield(); /* Optional, don't check rc. */ 352 353 size_t cbRead = 0; 354 if (cbSize) /* If we have nothing to write, take a shortcut. */ 355 { 356 /** @todo Not very efficient, but works for now. */ 357 rc = RTFileSeek(*pFile, cbOffset + cbWrittenTotal, 358 RTFILE_SEEK_BEGIN, NULL /* poffActual */); 359 if (RT_SUCCESS(rc)) 360 { 361 rc = RTFileRead(*pFile, (uint8_t*)byBuf, 362 RT_MIN((size_t)cbToRead, sizeof(byBuf)), &cbRead); 363 /* 364 * Some other error occured? There might be a chance that RTFileRead 365 * could not resolve/map the native error code to an IPRT code, so just 366 * print a generic error. 367 */ 368 if (RT_FAILURE(rc)) 369 { 370 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 371 Utf8StrFmt(GuestSession::tr("Could not read from host file \"%s\" (%Rrc)"), 372 strSource.c_str(), rc)); 373 break; 374 } 375 } 376 else 377 { 378 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 379 Utf8StrFmt(GuestSession::tr("Seeking host file \"%s\" to offset %RU64 failed: %Rrc"), 380 strSource.c_str(), cbWrittenTotal, rc)); 381 break; 382 } 383 } 384 385 uint32_t fFlags = ProcessInputFlag_None; 386 387 /* Did we reach the end of the content we want to transfer (last chunk)? */ 388 if ( (cbRead < sizeof(byBuf)) 389 /* Did we reach the last block which is exactly _64K? */ 390 || (cbToRead - cbRead == 0) 391 /* ... or does the user want to cancel? */ 392 || ( !mProgress.isNull() 393 && SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled))) 394 && fCanceled) 395 ) 396 { 397 LogFlowThisFunc(("Writing last chunk cbRead=%RU64\n", cbRead)); 398 fFlags |= ProcessInputFlag_EndOfFile; 399 } 400 401 uint32_t cbWritten; 402 Assert(sizeof(byBuf) >= cbRead); 403 rc = pProcess->i_writeData(0 /* StdIn */, fFlags, 404 byBuf, cbRead, 405 msTimeout, &cbWritten, &guestRc); 406 if (RT_FAILURE(rc)) 407 { 408 switch (rc) 409 { 410 case VERR_GSTCTL_GUEST_ERROR: 411 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 412 GuestProcess::i_guestErrorToString(guestRc)); 413 break; 414 415 default: 416 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 417 Utf8StrFmt(GuestSession::tr("Writing to guest file \"%s\" (offset %RU64) failed: %Rrc"), 418 strDest.c_str(), cbWrittenTotal, rc)); 419 break; 420 } 421 422 break; 423 } 424 425 /* Only subtract bytes reported written by the guest. */ 426 Assert(cbToRead >= cbWritten); 427 cbToRead -= cbWritten; 428 429 /* Update total bytes written to the guest. */ 430 cbWrittenTotal += cbWritten; 431 Assert(cbWrittenTotal <= cbSize); 432 433 LogFlowThisFunc(("rc=%Rrc, cbWritten=%RU32, cbToRead=%RU64, cbWrittenTotal=%RU64, cbFileSize=%RU64\n", 434 rc, cbWritten, cbToRead, cbWrittenTotal, cbSize)); 435 436 /* Did the user cancel the operation above? */ 437 if (fCanceled) 438 break; 439 440 /* Update the progress. 441 * Watch out for division by zero. */ 442 cbSize > 0 443 ? rc = setProgress((ULONG)(cbWrittenTotal * 100 / cbSize)) 444 : rc = setProgress(100); 445 if (RT_FAILURE(rc)) 446 break; 447 448 /* End of file reached? */ 449 if (!cbToRead) 450 break; 451 } /* for */ 452 453 LogFlowThisFunc(("Copy loop ended with rc=%Rrc, cbToRead=%RU64, cbWrittenTotal=%RU64, cbFileSize=%RU64\n", 454 rc, cbToRead, cbWrittenTotal, cbSize)); 455 456 /* 457 * Wait on termination of guest process until it completed all operations. 458 */ 459 if ( !fCanceled 460 || RT_SUCCESS(rc)) 461 { 462 rc = pProcess->i_waitFor(ProcessWaitForFlag_Terminate, msTimeout, waitRes, &guestRc); 463 if ( RT_FAILURE(rc) 464 || waitRes != ProcessWaitResult_Terminate) 465 { 466 if (RT_FAILURE(rc)) 467 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 468 Utf8StrFmt( 469 GuestSession::tr("Waiting on termination for copying file \"%s\" to guest failed: %Rrc"), 470 strSource.c_str(), rc)); 471 else 472 { 473 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 474 Utf8StrFmt(GuestSession::tr( 475 "Waiting on termination for copying file \"%s\" to guest failed with wait result %ld"), 476 strSource.c_str(), waitRes)); 477 rc = VERR_GENERAL_FAILURE; /* Fudge. */ 478 } 479 } 480 } 481 389 482 if (RT_SUCCESS(rc)) 390 483 { 391 ProcessWaitResult_T waitRes; 392 BYTE byBuf[_64K]; 393 394 BOOL fCanceled = FALSE; 395 uint64_t cbWrittenTotal = 0; 396 uint64_t cbToRead = mSourceSize; 397 398 for (;;) 399 { 400 rc = pProcess->i_waitFor(ProcessWaitForFlag_StdIn, msTimeout, waitRes, &guestRc); 401 if ( RT_FAILURE(rc) 402 || ( waitRes != ProcessWaitResult_StdIn 403 && waitRes != ProcessWaitResult_WaitFlagNotSupported)) 404 { 484 /* 485 * Newer VBoxService toolbox versions report what went wrong via exit code. 486 * So handle this first. 487 */ 488 /** @todo This code sequence is duplicated in CopyFrom... */ 489 ProcessStatus_T procStatus = ProcessStatus_TerminatedAbnormally; 490 HRESULT hrc = pProcess->COMGETTER(Status(&procStatus)); 491 if (!SUCCEEDED(hrc)) 492 procStatus = ProcessStatus_TerminatedAbnormally; 493 494 LONG exitCode = 42424242; 495 hrc = pProcess->COMGETTER(ExitCode(&exitCode)); 496 if (!SUCCEEDED(hrc)) 497 exitCode = 42424242; 498 499 if ( procStatus != ProcessStatus_TerminatedNormally 500 || exitCode != 0) 501 { 502 LogFlowThisFunc(("procStatus=%d, exitCode=%d\n", procStatus, exitCode)); 503 if (procStatus == ProcessStatus_TerminatedNormally) 504 rc = GuestProcessTool::i_exitCodeToRc(procInfo, exitCode); 505 else 506 rc = VERR_GENERAL_FAILURE; 507 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 508 Utf8StrFmt(GuestSession::tr("Copying file \"%s\" to guest failed: %Rrc"), 509 strSource.c_str(), rc)); 510 } 511 /* 512 * Even if we succeeded until here make sure to check whether we really transfered 513 * everything. 514 */ 515 else if ( cbSize > 0 516 && cbWrittenTotal == 0) 517 { 518 /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write 519 * to the destination -> access denied. */ 520 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 521 Utf8StrFmt(GuestSession::tr("Access denied when copying file \"%s\" to guest \"%s\""), 522 strSource.c_str(), strDest.c_str())); 523 rc = VERR_ACCESS_DENIED; 524 } 525 else if (cbWrittenTotal < cbSize) 526 { 527 /* If we did not copy all let the user know. */ 528 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 529 Utf8StrFmt(GuestSession::tr("Copying file \"%s\" to guest failed (%RU64/%RU64 bytes transfered)"), 530 strSource.c_str(), cbWrittenTotal, cbSize)); 531 rc = VERR_INTERRUPTED; 532 } 533 } 534 535 return rc; 536 } 537 538 /** 539 * Copies a file from the host to the guest. 540 * 541 * @return VBox status code. 542 * @param strSource Full path of source file on the host to copy. 543 * @param strDest Full destination path and file name (guest style) to copy file to. 544 * @param enmFileCopyFlags File copy flags. 545 */ 546 int GuestSessionTask::fileCopyToGuest(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags) 547 { 548 int rc; 549 550 /* Does our source file exist? */ 551 if (!RTFileExists(strSource.c_str())) 552 { 553 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 554 Utf8StrFmt(GuestSession::tr("Host file \"%s\" does not exist or is not a file"), 555 strSource.c_str())); 556 rc = VERR_FILE_NOT_FOUND; 557 } 558 else 559 { 560 RTFILE hFile; 561 rc = RTFileOpen(&hFile, strSource.c_str(), 562 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE); 563 if (RT_FAILURE(rc)) 564 { 565 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 566 Utf8StrFmt(GuestSession::tr("Could not open host file \"%s\" for reading: %Rrc"), 567 strSource.c_str(), rc)); 568 } 569 else 570 { 571 uint64_t cbSize; 572 rc = RTFileGetSize(hFile, &cbSize); 573 if (RT_FAILURE(rc)) 574 { 575 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 576 Utf8StrFmt(GuestSession::tr("Could not query host file size of \"%s\": %Rrc"), 577 strSource.c_str(), rc)); 578 } 579 else 580 rc = fileCopyToGuestEx(strSource, strDest, enmFileCopyFlags, &hFile, 0 /* Offset */, cbSize); 581 582 RTFileClose(hFile); 583 } 584 } 585 586 return rc; 587 } 588 589 /** 590 * Translates a source path to a destination path (can be both sides, 591 * either host or guest). The source root is needed to determine the start 592 * of the relative source path which also needs to present in the destination 593 * path. 594 * 595 * @return IPRT status code. 596 * @param strSourceRoot Source root path. No trailing directory slash! 597 * @param strSource Actual source to transform. Must begin with 598 * the source root path! 599 * @param strDest Destination path. 600 * @param strOut where to store the output path. 601 */ 602 int GuestSessionTask::pathConstructOnGuest(const Utf8Str &strSourceRoot, const Utf8Str &strSource, 603 const Utf8Str &strDest, Utf8Str &strOut) 604 { 605 RT_NOREF(strSourceRoot, strSource, strDest, strOut); 606 return VINF_SUCCESS; 607 } 608 609 SessionTaskOpen::SessionTaskOpen(GuestSession *pSession, 610 uint32_t uFlags, 611 uint32_t uTimeoutMS) 612 : GuestSessionTask(pSession), 613 mFlags(uFlags), 614 mTimeoutMS(uTimeoutMS) 615 { 616 m_strTaskName = "gctlSesOpen"; 617 } 618 619 SessionTaskOpen::~SessionTaskOpen(void) 620 { 621 622 } 623 624 int SessionTaskOpen::Run(void) 625 { 626 LogFlowThisFuncEnter(); 627 628 AutoCaller autoCaller(mSession); 629 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 630 631 int vrc = mSession->i_startSessionInternal(NULL /*pvrcGuest*/); 632 /* Nothing to do here anymore. */ 633 634 LogFlowFuncLeaveRC(vrc); 635 return vrc; 636 } 637 638 SessionTaskCopyDirTo::SessionTaskCopyDirTo(GuestSession *pSession, 639 const Utf8Str &strSource, const Utf8Str &strDest, const Utf8Str &strFilter, 640 DirectoryCopyFlags_T enmDirCopyFlags) 641 : GuestSessionTask(pSession) 642 , mSource(strSource) 643 , mDest(strDest) 644 , mFilter(strFilter) 645 , mDirCopyFlags(enmDirCopyFlags) 646 { 647 m_strTaskName = "gctlCopyDirTo"; 648 } 649 650 SessionTaskCopyDirTo::~SessionTaskCopyDirTo(void) 651 { 652 653 } 654 655 /** 656 * Copys a directory (tree) from host to the guest. 657 * 658 * @return IPRT status code. 659 * @param strSource Source directory on the host to copy to the guest. 660 * @param strFilter DOS-style wildcard filter (?, *). Optional. 661 * @param strDest Destination directory on the guest. 662 * @param fRecursive, Whther to recursively copy the directory contents or not. 663 * @param fFollowSymlinks Whether to follow symlinks or not. 664 * @param enmDirCopyFlags Directory copy flags. 665 * @param strSubDir Current sub directory to handle. Needs to NULL and only 666 * is needed for recursion. 667 */ 668 int SessionTaskCopyDirTo::directoryCopyToGuest(const Utf8Str &strSource, const Utf8Str &strFilter, 669 const Utf8Str &strDest, bool fRecursive, bool fFollowSymlinks, 670 const Utf8Str &strSubDir /* For recursion. */) 671 { 672 Utf8Str strSrcDir = strSource; 673 Utf8Str strDstDir = strDest; 674 Utf8Str strSrcSubDir = strSubDir; 675 676 /* Validation and sanity. */ 677 if ( !strSrcDir.endsWith("/") 678 && !strSrcDir.endsWith("\\")) 679 strSrcDir += "/"; 680 681 if ( !strDstDir.endsWith("/") 682 && !strDstDir.endsWith("\\")) 683 strDstDir+= "/"; 684 685 if ( strSrcSubDir.isNotEmpty() /* Optional, for recursion. */ 686 && !strSrcSubDir.endsWith("/") 687 && !strSrcSubDir.endsWith("\\")) 688 strSrcSubDir += "/"; 689 690 Utf8Str strSrcCur = strSrcDir + strSrcSubDir; 691 692 LogFlowFunc(("Entering '%s'\n", strSrcCur.c_str())); 693 694 int rc; 695 696 if (strSrcSubDir.isNotEmpty()) 697 { 698 const uint32_t uMode = 0700; /** @todo */ 699 rc = directoryCreate(strDstDir + strSrcSubDir, DirectoryCreateFlag_Parents, uMode, fFollowSymlinks); 700 if (RT_FAILURE(rc)) 701 return rc; 702 } 703 704 /* 705 * Open directory without a filter - RTDirOpenFiltered unfortunately 706 * cannot handle sub directories so we have to do the filtering ourselves. 707 */ 708 RTDIR hDir; 709 rc = RTDirOpen(&hDir, strSrcCur.c_str()); 710 if (RT_SUCCESS(rc)) 711 { 712 /* 713 * Enumerate the directory tree. 714 */ 715 size_t cbDirEntry = 0; 716 PRTDIRENTRYEX pDirEntry = NULL; 717 while (RT_SUCCESS(rc)) 718 { 719 rc = RTDirReadExA(hDir, &pDirEntry, &cbDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK); 720 if (RT_FAILURE(rc)) 721 { 722 if (rc == VERR_NO_MORE_FILES) 723 rc = VINF_SUCCESS; 405 724 break; 406 725 } 407 726 408 /* If the guest does not support waiting for stdin, we now yield in 409 * order to reduce the CPU load due to busy waiting. */ 410 if (waitRes == ProcessWaitResult_WaitFlagNotSupported) 411 RTThreadYield(); /* Optional, don't check rc. */ 412 413 size_t cbRead = 0; 414 if (mSourceSize) /* If we have nothing to write, take a shortcut. */ 415 { 416 /** @todo Not very efficient, but works for now. */ 417 rc = RTFileSeek(*pFile, mSourceOffset + cbWrittenTotal, 418 RTFILE_SEEK_BEGIN, NULL /* poffActual */); 419 if (RT_SUCCESS(rc)) 420 { 421 rc = RTFileRead(*pFile, (uint8_t*)byBuf, 422 RT_MIN((size_t)cbToRead, sizeof(byBuf)), &cbRead); 423 /* 424 * Some other error occured? There might be a chance that RTFileRead 425 * could not resolve/map the native error code to an IPRT code, so just 426 * print a generic error. 427 */ 428 if (RT_FAILURE(rc)) 727 #ifdef LOG_ENABLED 728 Utf8Str strDbgCurEntry = strSrcCur + Utf8Str(pDirEntry->szName); 729 LogFlowFunc(("Handling '%s' (fMode=0x%x)\n", strDbgCurEntry.c_str(), pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK)); 730 #endif 731 switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK) 732 { 733 case RTFS_TYPE_DIRECTORY: 734 { 735 /* Skip "." and ".." entries. */ 736 if (RTDirEntryExIsStdDotLink(pDirEntry)) 737 break; 738 739 bool fSkip = false; 740 741 if ( strFilter.isNotEmpty() 742 && !RTStrSimplePatternMatch(strFilter.c_str(), pDirEntry->szName)) 743 fSkip = true; 744 745 if ( fRecursive 746 && !fSkip) 747 rc = directoryCopyToGuest(strSrcDir, strFilter, strDstDir, fRecursive, fFollowSymlinks, 748 strSrcSubDir + Utf8Str(pDirEntry->szName)); 749 break; 750 } 751 752 case RTFS_TYPE_SYMLINK: 753 if (fFollowSymlinks) 754 { /* Fall through to next case is intentional. */ } 755 else 756 break; 757 RT_FALL_THRU(); 758 759 case RTFS_TYPE_FILE: 760 { 761 if ( strFilter.isNotEmpty() 762 && !RTStrSimplePatternMatch(strFilter.c_str(), pDirEntry->szName)) 429 763 { 430 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 431 Utf8StrFmt(GuestSession::tr("Could not read from host file \"%s\" (%Rrc)"), 432 mSource.c_str(), rc)); 433 break; 764 break; /* Filter does not match. */ 434 765 } 435 } 436 else 437 { 438 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 439 Utf8StrFmt(GuestSession::tr("Seeking host file \"%s\" to offset %RU64 failed: %Rrc"), 440 mSource.c_str(), cbWrittenTotal, rc)); 766 767 if (RT_SUCCESS(rc)) 768 { 769 Utf8Str strSrcFile = strSrcDir + strSrcSubDir + Utf8Str(pDirEntry->szName); 770 Utf8Str strDstFile = strDstDir + strSrcSubDir + Utf8Str(pDirEntry->szName); 771 rc = fileCopyToGuest(strSrcFile, strDstFile, FileCopyFlag_None); 772 } 441 773 break; 442 774 } 443 } 444 445 uint32_t fFlags = ProcessInputFlag_None; 446 447 /* Did we reach the end of the content we want to transfer (last chunk)? */ 448 if ( (cbRead < sizeof(byBuf)) 449 /* Did we reach the last block which is exactly _64K? */ 450 || (cbToRead - cbRead == 0) 451 /* ... or does the user want to cancel? */ 452 || ( !mProgress.isNull() 453 && SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled))) 454 && fCanceled) 455 ) 456 { 457 LogFlowThisFunc(("Writing last chunk cbRead=%RU64\n", cbRead)); 458 fFlags |= ProcessInputFlag_EndOfFile; 459 } 460 461 uint32_t cbWritten; 462 Assert(sizeof(byBuf) >= cbRead); 463 rc = pProcess->i_writeData(0 /* StdIn */, fFlags, 464 byBuf, cbRead, 465 msTimeout, &cbWritten, &guestRc); 466 if (RT_FAILURE(rc)) 467 { 468 switch (rc) 469 { 470 case VERR_GSTCTL_GUEST_ERROR: 471 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 472 GuestProcess::i_guestErrorToString(guestRc)); 473 break; 474 475 default: 476 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 477 Utf8StrFmt(GuestSession::tr("Writing to guest file \"%s\" (offset %RU64) failed: %Rrc"), 478 mDest.c_str(), cbWrittenTotal, rc)); 479 break; 480 } 481 482 break; 483 } 484 485 /* Only subtract bytes reported written by the guest. */ 486 Assert(cbToRead >= cbWritten); 487 cbToRead -= cbWritten; 488 489 /* Update total bytes written to the guest. */ 490 cbWrittenTotal += cbWritten; 491 Assert(cbWrittenTotal <= mSourceSize); 492 493 LogFlowThisFunc(("rc=%Rrc, cbWritten=%RU32, cbToRead=%RU64, cbWrittenTotal=%RU64, cbFileSize=%RU64\n", 494 rc, cbWritten, cbToRead, cbWrittenTotal, mSourceSize)); 495 496 /* Did the user cancel the operation above? */ 497 if (fCanceled) 498 break; 499 500 /* Update the progress. 501 * Watch out for division by zero. */ 502 mSourceSize > 0 503 ? rc = setProgress((ULONG)(cbWrittenTotal * 100 / mSourceSize)) 504 : rc = setProgress(100); 775 776 default: 777 break; 778 } 505 779 if (RT_FAILURE(rc)) 506 780 break; 507 508 /* End of file reached? */ 509 if (!cbToRead) 510 break; 511 } /* for */ 512 513 LogFlowThisFunc(("Copy loop ended with rc=%Rrc, cbToRead=%RU64, cbWrittenTotal=%RU64, cbFileSize=%RU64\n", 514 rc, cbToRead, cbWrittenTotal, mSourceSize)); 515 516 /* 517 * Wait on termination of guest process until it completed all operations. 518 */ 519 if ( !fCanceled 520 || RT_SUCCESS(rc)) 521 { 522 rc = pProcess->i_waitFor(ProcessWaitForFlag_Terminate, msTimeout, waitRes, &guestRc); 523 if ( RT_FAILURE(rc) 524 || waitRes != ProcessWaitResult_Terminate) 525 { 526 if (RT_FAILURE(rc)) 527 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 528 Utf8StrFmt( 529 GuestSession::tr("Waiting on termination for copying file \"%s\" to guest failed: %Rrc"), 530 mSource.c_str(), rc)); 531 else 532 { 533 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 534 Utf8StrFmt(GuestSession::tr( 535 "Waiting on termination for copying file \"%s\" to guest failed with wait result %ld"), 536 mSource.c_str(), waitRes)); 537 rc = VERR_GENERAL_FAILURE; /* Fudge. */ 538 } 539 } 540 } 541 542 if (RT_SUCCESS(rc)) 543 { 544 /* 545 * Newer VBoxService toolbox versions report what went wrong via exit code. 546 * So handle this first. 547 */ 548 /** @todo This code sequence is duplicated in CopyFrom... */ 549 ProcessStatus_T procStatus = ProcessStatus_TerminatedAbnormally; 550 HRESULT hrc = pProcess->COMGETTER(Status(&procStatus)); 551 if (!SUCCEEDED(hrc)) 552 procStatus = ProcessStatus_TerminatedAbnormally; 553 554 LONG exitCode = 42424242; 555 hrc = pProcess->COMGETTER(ExitCode(&exitCode)); 556 if (!SUCCEEDED(hrc)) 557 exitCode = 42424242; 558 559 if ( procStatus != ProcessStatus_TerminatedNormally 560 || exitCode != 0) 561 { 562 LogFlowThisFunc(("procStatus=%d, exitCode=%d\n", procStatus, exitCode)); 563 if (procStatus == ProcessStatus_TerminatedNormally) 564 rc = GuestProcessTool::i_exitCodeToRc(procInfo, exitCode); 565 else 566 rc = VERR_GENERAL_FAILURE; 567 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 568 Utf8StrFmt(GuestSession::tr("Copying file \"%s\" to guest failed: %Rrc"), 569 mSource.c_str(), rc)); 570 } 571 /* 572 * Even if we succeeded until here make sure to check whether we really transfered 573 * everything. 574 */ 575 else if ( mSourceSize > 0 576 && cbWrittenTotal == 0) 577 { 578 /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write 579 * to the destination -> access denied. */ 580 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 581 Utf8StrFmt(GuestSession::tr("Access denied when copying file \"%s\" to guest \"%s\""), 582 mSource.c_str(), mDest.c_str())); 583 rc = VERR_ACCESS_DENIED; 584 } 585 else if (cbWrittenTotal < mSourceSize) 586 { 587 /* If we did not copy all let the user know. */ 588 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 589 Utf8StrFmt(GuestSession::tr("Copying file \"%s\" to guest failed (%RU64/%RU64 bytes transfered)"), 590 mSource.c_str(), cbWrittenTotal, mSourceSize)); 591 rc = VERR_INTERRUPTED; 592 } 593 else 594 rc = setProgressSuccess(); 595 } 596 } /* processCreateExInteral */ 597 598 if (!mSourceFile) /* Only close locally opened files. */ 599 RTFileClose(*pFile); 781 } 782 783 RTDirReadExAFree(&pDirEntry, &cbDirEntry); 784 RTDirClose(hDir); 785 } 786 787 LogFlowFunc(("Leaving '%s', rc=%Rrc\n", strSrcCur.c_str(), rc)); 788 return rc; 789 } 790 791 int SessionTaskCopyDirTo::Run(void) 792 { 793 LogFlowThisFuncEnter(); 794 795 AutoCaller autoCaller(mSession); 796 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 797 798 const bool fRecursive = true; /** @todo Make this configurable. */ 799 const bool fFollowSymlinks = true; /** @todo Make this configurable. */ 800 const uint32_t uDirMode = 0700; /* Play safe by default. */ 801 802 /* Create the root target directory on the guest. 803 * The target directory might already exist on the guest (based on mDirCopyFlags). */ 804 int rc = directoryCreate(mDest, DirectoryCreateFlag_None, uDirMode, fFollowSymlinks); 805 if ( rc == VWRN_ALREADY_EXISTS 806 && !(mDirCopyFlags & DirectoryCopyFlags_CopyIntoExisting)) 807 { 808 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 809 Utf8StrFmt(GuestSession::tr("Destination directory \"%s\" exists when it must not"), mDest.c_str())); 810 } 811 812 if (RT_FAILURE(rc)) 813 return rc; 814 815 /* At this point the directory on the guest was created and (hopefully) is ready 816 * to receive further content. */ 817 rc = directoryCopyToGuest(mSource, mFilter, mDest, fRecursive, fFollowSymlinks, 818 "" /* strSubDir; for recursion */); 819 if (RT_SUCCESS(rc)) 820 rc = setProgressSuccess(); 600 821 601 822 LogFlowFuncLeaveRC(rc); … … 603 824 } 604 825 605 SessionTaskCopyFrom::SessionTaskCopyFrom(GuestSession *pSession, 606 const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags) 607 : GuestSessionTask(pSession) 826 SessionTaskCopyFileTo::SessionTaskCopyFileTo(GuestSession *pSession, 827 const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags) 828 : GuestSessionTask(pSession), 829 mSource(strSource), 830 mSourceFile(NULL), 831 mSourceOffset(0), 832 mSourceSize(0), 833 mDest(strDest) 834 { 835 mCopyFileFlags = uFlags; 836 m_strTaskName = "gctlCopyFileTo"; 837 } 838 839 SessionTaskCopyFileTo::SessionTaskCopyFileTo(GuestSession *pSession, 840 PRTFILE pSourceFile, size_t cbSourceOffset, uint64_t cbSourceSize, 841 const Utf8Str &strDest, uint32_t uFlags) 842 : GuestSessionTask(pSession) 843 { 844 mSourceFile = pSourceFile; 845 mSourceOffset = cbSourceOffset; 846 mSourceSize = cbSourceSize; 847 mDest = strDest; 848 mCopyFileFlags = uFlags; 849 m_strTaskName = "gctlCopyFileToWithHandle"; 850 } 851 852 SessionTaskCopyFileTo::~SessionTaskCopyFileTo(void) 853 { 854 855 } 856 857 int SessionTaskCopyFileTo::Run(void) 858 { 859 LogFlowThisFuncEnter(); 860 861 AutoCaller autoCaller(mSession); 862 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 863 864 if (mSource.isEmpty()) 865 { 866 setProgressErrorMsg(VBOX_E_IPRT_ERROR, Utf8StrFmt(GuestSession::tr("No source file specified"))); 867 return VERR_INVALID_PARAMETER; 868 } 869 870 if (mDest.isEmpty()) 871 { 872 setProgressErrorMsg(VBOX_E_IPRT_ERROR, Utf8StrFmt(GuestSession::tr("No destintation file specified"))); 873 return VERR_INVALID_PARAMETER; 874 } 875 876 const char *pszFileName = RTPathFilename(mSource.c_str()); 877 878 if ( !pszFileName 879 || !RTFileExists(pszFileName)) 880 { 881 setProgressErrorMsg(VBOX_E_IPRT_ERROR, Utf8StrFmt(GuestSession::tr("Source file not valid or does not exist"))); 882 return VERR_FILE_NOT_FOUND; 883 } 884 885 if (mCopyFileFlags) 886 { 887 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 888 Utf8StrFmt(GuestSession::tr("Copy flags (%#x) not implemented yet"), 889 mCopyFileFlags)); 890 return VERR_NOT_IMPLEMENTED; 891 } 892 893 /** @todo Try to lock the destination directory on the guest here first? */ 894 895 int rc = VINF_SUCCESS; 896 897 /* 898 * Query information about our destination first. 899 */ 900 if ( mDest.endsWith("/") 901 || mDest.endsWith("\\")) 902 { 903 int guestRc; 904 GuestFsObjData objData; 905 rc = mSession->i_fsQueryInfoInternal(mDest, true /* fFollowSymlinks */, objData, &guestRc); 906 if (RT_SUCCESS(rc)) 907 { 908 if (objData.mType != FsObjType_Directory) 909 { 910 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 911 Utf8StrFmt(GuestSession::tr("Path \"%s\" is not a directory on guest"), mDest.c_str())); 912 rc = VERR_NOT_A_DIRECTORY; 913 } 914 else 915 { 916 AssertPtr(pszFileName); 917 mDest += pszFileName; 918 } 919 } 920 else 921 { 922 switch (rc) 923 { 924 case VERR_GSTCTL_GUEST_ERROR: 925 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 926 GuestProcess::i_guestErrorToString(guestRc)); 927 break; 928 929 default: 930 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 931 Utf8StrFmt(GuestSession::tr("Unable to query information for directory \"%s\" on the guest: %Rrc"), 932 mDest.c_str(), rc)); 933 break; 934 } 935 } 936 } 937 938 if (RT_SUCCESS(rc)) 939 { 940 if (mSourceFile) /* Use existing file handle. */ 941 rc = fileCopyToGuestEx(mSource, mDest, mCopyFileFlags, 942 mSourceFile, mSourceOffset, mSourceSize); 943 else 944 rc = fileCopyToGuest(mSource, mDest, mCopyFileFlags); 945 946 if (RT_SUCCESS(rc)) 947 rc = setProgressSuccess(); 948 } 949 950 LogFlowFuncLeaveRC(rc); 951 return rc; 952 } 953 954 SessionTaskCopyFileFrom::SessionTaskCopyFileFrom(GuestSession *pSession, 955 const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags) 956 : GuestSessionTask(pSession) 608 957 { 609 958 mSource = strSource; 610 959 mDest = strDest; 611 960 mFlags = uFlags; 612 m_strTaskName = "gctlC pyFrom";613 } 614 615 SessionTaskCopyF rom::~SessionTaskCopyFrom(void)616 { 617 618 } 619 620 int SessionTaskCopyF rom::Run(void)961 m_strTaskName = "gctlCopyFileFrom"; 962 } 963 964 SessionTaskCopyFileFrom::~SessionTaskCopyFileFrom(void) 965 { 966 967 } 968 969 int SessionTaskCopyFileFrom::Run(void) 621 970 { 622 971 LogFlowThisFuncEnter(); 623 972 624 ComObjPtr<GuestSession> pSession = mSession; 625 Assert(!pSession.isNull()); 626 627 AutoCaller autoCaller(pSession); 973 AutoCaller autoCaller(mSession); 628 974 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 629 975 … … 637 983 */ 638 984 GuestFsObjData objData; int guestRc; 639 int rc = pSession->i_fileQueryInfoInternal(Utf8Str(mSource), false /*fFollowSymlinks*/, objData, &guestRc);985 int rc = mSession->i_fileQueryInfoInternal(Utf8Str(mSource), false /*fFollowSymlinks*/, objData, &guestRc); 640 986 if (RT_FAILURE(rc)) 641 987 { … … 676 1022 /* Startup process. */ 677 1023 ComObjPtr<GuestProcess> pProcess; 678 rc = pSession->i_processCreateExInternal(procInfo, pProcess);1024 rc = mSession->i_processCreateExInternal(procInfo, pProcess); 679 1025 if (RT_SUCCESS(rc)) 680 1026 rc = pProcess->i_startProcess(msTimeout, &guestRc); … … 899 1245 } 900 1246 901 int SessionTaskUpdateAdditions::i_addProcessArguments(ProcessArguments &aArgumentsDest, 902 const ProcessArguments &aArgumentsSource) 1247 int SessionTaskUpdateAdditions::addProcessArguments(ProcessArguments &aArgumentsDest, const ProcessArguments &aArgumentsSource) 903 1248 { 904 1249 int rc = VINF_SUCCESS; … … 938 1283 } 939 1284 940 int SessionTaskUpdateAdditions:: i_copyFileToGuest(GuestSession *pSession, PRTISOFSFILE pISO,941 942 1285 int SessionTaskUpdateAdditions::copyFileToGuest(GuestSession *pSession, PRTISOFSFILE pISO, 1286 Utf8Str const &strFileSource, const Utf8Str &strFileDest, 1287 bool fOptional, uint32_t *pcbSize) 943 1288 { 944 1289 AssertPtrReturn(pSession, VERR_INVALID_POINTER); … … 971 1316 if (RT_SUCCESS(rc)) 972 1317 { 973 SessionTaskCopy To *pTask = NULL;1318 SessionTaskCopyFileTo *pTask = NULL; 974 1319 ComObjPtr<Progress> pProgressCopyTo; 975 1320 try … … 977 1322 try 978 1323 { 979 pTask = new SessionTaskCopy To(pSession /* GuestSession */,980 &pISO->file, cbOffset, cbSize,981 strFileDest, FileCopyFlag_None);1324 pTask = new SessionTaskCopyFileTo(pSession /* GuestSession */, 1325 &pISO->file, cbOffset, cbSize, 1326 strFileDest, FileCopyFlag_None); 982 1327 } 983 1328 catch(...) … … 1091 1436 } 1092 1437 1093 int SessionTaskUpdateAdditions:: i_runFileOnGuest(GuestSession *pSession, GuestProcessStartupInfo &procInfo)1438 int SessionTaskUpdateAdditions::runFileOnGuest(GuestSession *pSession, GuestProcessStartupInfo &procInfo) 1094 1439 { 1095 1440 AssertPtrReturn(pSession, VERR_INVALID_POINTER); … … 1480 1825 /* Add optional installer command line arguments from the API to the 1481 1826 * installer's startup info. */ 1482 rc = i_addProcessArguments(siInstaller.mArguments, mArguments);1827 rc = addProcessArguments(siInstaller.mArguments, mArguments); 1483 1828 AssertRC(rc); 1484 1829 /* If the caller does not want to wait for out guest update process to end, … … 1520 1865 if (itFiles->fFlags & UPDATEFILE_FLAG_OPTIONAL) 1521 1866 fOptional = true; 1522 rc = i_copyFileToGuest(pSession, &iso, itFiles->strSource, itFiles->strDest,1867 rc = copyFileToGuest(pSession, &iso, itFiles->strSource, itFiles->strDest, 1523 1868 fOptional, NULL /* cbSize */); 1524 1869 if (RT_FAILURE(rc)) … … 1557 1902 if (itFiles->fFlags & UPDATEFILE_FLAG_EXECUTE) 1558 1903 { 1559 rc = i_runFileOnGuest(pSession, itFiles->mProcInfo);1904 rc = runFileOnGuest(pSession, itFiles->mProcInfo); 1560 1905 if (RT_FAILURE(rc)) 1561 1906 break;
Note:
See TracChangeset
for help on using the changeset viewer.