Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

551 lines
16 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. copyfile.c
  5. Abstract:
  6. File copy functions
  7. The code in this source file traverses a drive tree and calls
  8. an external callback function for each file. An INF can be
  9. provided to exclude files and/or directories from enumeration.
  10. Author:
  11. Mike Condra 16-Aug-1996
  12. Revision History:
  13. calinn 29-Ian-1998 Modified CopyFileCallback to reset directory attributes for delete op.
  14. jimschm 20-Dec-1996 Modified return codes
  15. --*/
  16. #include "pch.h"
  17. #include "migshared.h"
  18. #ifdef UNICODE
  19. BOOL
  20. CALLBACK
  21. CopyFileCallbackA(
  22. LPCSTR szFullFileSpecIn,
  23. LPCSTR DontCare,
  24. WIN32_FIND_DATAA *pFindData,
  25. DWORD dwEnumHandle,
  26. LPVOID pVoid,
  27. PDWORD CurrentDirData
  28. )
  29. /*
  30. This function is the built-in callback for CopyTree. Its purpose is to
  31. build the target filespec, give the user-supplied callback a chance to
  32. veto the copy, then perform the copy and any directory creation it
  33. requires. The signature of this function is the generic callback
  34. used for EnumerateTree.
  35. */
  36. {
  37. COPYTREE_PARAMSA *pCopyParams = (COPYTREE_PARAMSA*)pVoid;
  38. int nCharsInFullFileSpec = ByteCountA (szFullFileSpecIn);
  39. INT rc;
  40. // Set return code
  41. if (COPYTREE_IGNORE_ERRORS & pCopyParams->flags)
  42. rc = CALLBACK_CONTINUE;
  43. else
  44. rc = CALLBACK_FAILED;
  45. // Build output path
  46. if (pCopyParams->szEnumRootOutWack)
  47. {
  48. StringCopyA(pCopyParams->szFullFileSpecOut, pCopyParams->szEnumRootOutWack);
  49. StringCatA (pCopyParams->szFullFileSpecOut, szFullFileSpecIn + pCopyParams->nCharsInRootInWack);
  50. }
  51. //
  52. // If a callback was supplied, give it a chance to veto the copy. This callback is
  53. // different from the one given to an EnumerateTree function, since the latter can
  54. // terminate enumeration by returning FALSE.
  55. //
  56. if (pCopyParams->pfnCallback)
  57. {
  58. if (!pCopyParams->pfnCallback(
  59. szFullFileSpecIn,
  60. pCopyParams->szFullFileSpecOut,
  61. pFindData,
  62. dwEnumHandle,
  63. pVoid,
  64. CurrentDirData
  65. ))
  66. {
  67. return CALLBACK_CONTINUE;
  68. }
  69. }
  70. // Copy, move or delete the file if requested
  71. if ((COPYTREE_DOCOPY & pCopyParams->flags) ||
  72. (COPYTREE_DOMOVE & pCopyParams->flags))
  73. {
  74. BOOL fNoOverwrite = (0 != (COPYTREE_NOOVERWRITE & pCopyParams->flags));
  75. //
  76. // Create the directory. The function we call expects a full filename,
  77. // and considers the directory to end at the last wack. If this object
  78. // is a directory, we need to add at least a wack to make sure the last
  79. // path element is treated as part of the directory, not as a filename.
  80. //
  81. {
  82. CHAR strTemp[MAX_MBCHAR_PATH];
  83. StringCopyTcharCountA (strTemp, pCopyParams->szFullFileSpecOut, ARRAYSIZE(strTemp) - 1);
  84. if (pFindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  85. {
  86. AppendUncWackA(strTemp);
  87. }
  88. if (ERROR_SUCCESS != MakeSurePathExistsA(strTemp,FALSE))
  89. {
  90. return rc;
  91. }
  92. }
  93. //
  94. // Copy or move the file
  95. //
  96. if (0 == (pFindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  97. {
  98. if (COPYTREE_DOCOPY & pCopyParams->flags)
  99. {
  100. if (!CopyFileA(
  101. szFullFileSpecIn,
  102. pCopyParams->szFullFileSpecOut,
  103. fNoOverwrite
  104. ))
  105. {
  106. if (!fNoOverwrite)
  107. {
  108. return rc;
  109. }
  110. if (ERROR_FILE_EXISTS != GetLastError())
  111. {
  112. return rc;
  113. }
  114. }
  115. }
  116. else if (COPYTREE_DOMOVE & pCopyParams->flags)
  117. {
  118. // If allowed to overwrite, delete the target if it exists
  119. if (!fNoOverwrite && DoesFileExistA(pCopyParams->szFullFileSpecOut))
  120. {
  121. SetFileAttributesA (pCopyParams->szFullFileSpecOut, FILE_ATTRIBUTE_NORMAL);
  122. if (!DeleteFileA(pCopyParams->szFullFileSpecOut))
  123. {
  124. return rc;
  125. }
  126. }
  127. // Move the file
  128. if (!MoveFileA(
  129. szFullFileSpecIn,
  130. pCopyParams->szFullFileSpecOut
  131. ))
  132. {
  133. return rc;
  134. }
  135. }
  136. }
  137. //
  138. // Copy the source file-or-directory's attributes to the target
  139. //
  140. SetFileAttributesA(pCopyParams->szFullFileSpecOut,
  141. pFindData->dwFileAttributes);
  142. }
  143. else if (COPYTREE_DODELETE & pCopyParams->flags) {
  144. SetFileAttributesA (szFullFileSpecIn, FILE_ATTRIBUTE_NORMAL);
  145. if (pFindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  146. //
  147. // We don't care about the error. We won't stop the enumeration just
  148. // because we could not delete something.
  149. //
  150. RemoveDirectoryA (szFullFileSpecIn);
  151. }
  152. else {
  153. //
  154. // We don't care about the error. We won't stop the enumeration just
  155. // because we could not delete something.
  156. //
  157. DeleteFileA (szFullFileSpecIn);
  158. }
  159. }
  160. return CALLBACK_CONTINUE;
  161. }
  162. BOOL
  163. CALLBACK
  164. CopyFileCallbackW(
  165. LPCWSTR szFullFileSpecIn,
  166. LPCWSTR DontCare,
  167. WIN32_FIND_DATAW *pFindData,
  168. DWORD dwEnumHandle,
  169. LPVOID pVoid,
  170. PDWORD CurrentDirData
  171. )
  172. {
  173. COPYTREE_PARAMSW *pCopyParams = (COPYTREE_PARAMSW*)pVoid;
  174. int nCharsInFullFileSpec = wcslen (szFullFileSpecIn);
  175. INT rc;
  176. // Set return code
  177. if (COPYTREE_IGNORE_ERRORS & pCopyParams->flags)
  178. rc = CALLBACK_CONTINUE;
  179. else
  180. rc = CALLBACK_FAILED;
  181. // Build output path
  182. if (pCopyParams->szEnumRootOutWack)
  183. {
  184. StringCopyW (pCopyParams->szFullFileSpecOut, pCopyParams->szEnumRootOutWack);
  185. StringCatW (pCopyParams->szFullFileSpecOut, szFullFileSpecIn + pCopyParams->nCharsInRootInWack);
  186. }
  187. //
  188. // If a callback was supplied, give it a chance to veto the copy. This callback is
  189. // different from the one given to an EnumerateTree function, since the latter can
  190. // terminate enumeration by returning FALSE.
  191. //
  192. if (pCopyParams->pfnCallback)
  193. {
  194. if (!pCopyParams->pfnCallback(
  195. szFullFileSpecIn,
  196. pCopyParams->szFullFileSpecOut,
  197. pFindData,
  198. dwEnumHandle,
  199. pVoid,
  200. CurrentDirData
  201. ))
  202. {
  203. return CALLBACK_CONTINUE;
  204. }
  205. }
  206. // Copy or move the file if requested
  207. if ((COPYTREE_DOCOPY & pCopyParams->flags) ||
  208. (COPYTREE_DOMOVE & pCopyParams->flags))
  209. {
  210. BOOL fNoOverwrite = (0 != (COPYTREE_NOOVERWRITE & pCopyParams->flags));
  211. //
  212. // Create the directory. The function we call expects a full filename,
  213. // and considers the directory to end at the last wack. If this object
  214. // is a directory, we need to add at least a wack to make sure the last
  215. // path element is treated as part of the directory, not as a filename.
  216. //
  217. {
  218. WCHAR strTemp[MAX_WCHAR_PATH];
  219. StringCopyTcharCountW (strTemp, pCopyParams->szFullFileSpecOut, ARRAYSIZE(strTemp) - 1);
  220. if (pFindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  221. {
  222. AppendUncWackW(strTemp);
  223. }
  224. if (ERROR_SUCCESS != MakeSurePathExistsW(strTemp,FALSE))
  225. {
  226. return rc;
  227. }
  228. }
  229. //
  230. // Copy or move the file
  231. //
  232. if (0 == (pFindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  233. {
  234. if (COPYTREE_DOCOPY & pCopyParams->flags)
  235. {
  236. DEBUGMSG ((DBG_NAUSEA, "Copying %s to %s", szFullFileSpecIn, pCopyParams->szFullFileSpecOut));
  237. if (!CopyFileW(
  238. szFullFileSpecIn,
  239. pCopyParams->szFullFileSpecOut,
  240. fNoOverwrite
  241. ))
  242. {
  243. if (!fNoOverwrite)
  244. {
  245. LOG ((LOG_ERROR, "CopyFileW failed. Could not copy %s to %s", szFullFileSpecIn, pCopyParams->szFullFileSpecOut));
  246. return rc;
  247. }
  248. if (ERROR_FILE_EXISTS != GetLastError())
  249. {
  250. LOG ((LOG_ERROR, "CopyFileW failed. Could not copy %s to %s", szFullFileSpecIn, pCopyParams->szFullFileSpecOut));
  251. return rc;
  252. }
  253. }
  254. }
  255. else if (COPYTREE_DOMOVE & pCopyParams->flags)
  256. {
  257. // If allowed to overwrite, delete the target if it exists
  258. if (!fNoOverwrite && DoesFileExistW(pCopyParams->szFullFileSpecOut))
  259. {
  260. SetFileAttributesW (pCopyParams->szFullFileSpecOut, FILE_ATTRIBUTE_NORMAL);
  261. if (!DeleteFileW(pCopyParams->szFullFileSpecOut))
  262. {
  263. LOG ((LOG_ERROR, "DeleteFileW failed. Could remove %s before moving", pCopyParams->szFullFileSpecOut));
  264. return rc;
  265. }
  266. }
  267. // Move the file
  268. if (!MoveFileW(
  269. szFullFileSpecIn,
  270. pCopyParams->szFullFileSpecOut
  271. ))
  272. {
  273. LOG ((LOG_ERROR, "MoveFileW failed. Could not move %s to %s", szFullFileSpecIn, pCopyParams->szFullFileSpecOut));
  274. return rc;
  275. }
  276. }
  277. }
  278. //
  279. // Copy the source file-or-directory's attributes to the target
  280. //
  281. SetFileAttributesW(pCopyParams->szFullFileSpecOut,
  282. pFindData->dwFileAttributes);
  283. }
  284. else if (COPYTREE_DODELETE & pCopyParams->flags) {
  285. SetFileAttributesW (szFullFileSpecIn, FILE_ATTRIBUTE_NORMAL);
  286. if (pFindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  287. DEBUGMSG ((DBG_NAUSEA, "Delete dir %ls", szFullFileSpecIn));
  288. //
  289. // We don't care about the error. We won't stop the enumeration just
  290. // because we could not delete something.
  291. //
  292. RemoveDirectoryW (szFullFileSpecIn);
  293. }
  294. else {
  295. DEBUGMSG ((DBG_NAUSEA, "Delete file %ls", szFullFileSpecIn));
  296. //
  297. // We don't care about the error. We won't stop the enumeration just
  298. // because we could not delete something.
  299. //
  300. DeleteFileW (szFullFileSpecIn);
  301. }
  302. }
  303. return CALLBACK_CONTINUE;
  304. }
  305. BOOL
  306. CopyTreeA(
  307. IN LPCSTR szEnumRootIn,
  308. IN LPCSTR szEnumRootOut,
  309. IN DWORD dwEnumHandle,
  310. IN DWORD flags,
  311. IN DWORD Levels,
  312. IN DWORD AttributeFilter,
  313. IN PEXCLUDEINFA ExcludeInfStruct, OPTIONAL
  314. IN FILEENUMPROCA pfnCallback, OPTIONAL
  315. IN FILEENUMFAILPROCA pfnFailCallback OPTIONAL
  316. )
  317. /*
  318. This function enumerates a subtree of a disk drive, and optionally
  319. copies it to another location. No check is made to ensure the target
  320. is not contained within the source tree -- this condition could lead
  321. to unpredictable results.
  322. The parameters are a superset of those for EnumerateTree. The caller-
  323. supplied optional callback function can veto the copying of individual
  324. files, but cannot (as of 9/10) end the enumeration.
  325. Directories will be created as necessary to complete the copy.
  326. */
  327. {
  328. COPYTREE_PARAMSA copyParams;
  329. CHAR szEnumRootInWack[MAX_MBCHAR_PATH];
  330. CHAR szEnumRootOutWack[MAX_MBCHAR_PATH];
  331. //
  332. // Build wacked copies of paths for use in parameter block.
  333. //
  334. //
  335. // Input path
  336. //
  337. StringCopyTcharCountA (szEnumRootInWack, szEnumRootIn, ARRAYSIZE(szEnumRootInWack) - 1);
  338. AppendUncWackA(szEnumRootInWack);
  339. copyParams.szEnumRootInWack = szEnumRootInWack;
  340. copyParams.nCharsInRootInWack = ByteCountA(szEnumRootInWack);
  341. //
  342. // If output path is NULL, store 0 length and a NULL ptr in param block.
  343. //
  344. if (NULL != szEnumRootOut)
  345. {
  346. StringCopyA(szEnumRootOutWack, szEnumRootOut);
  347. AppendUncWackA(szEnumRootOutWack);
  348. copyParams.szEnumRootOutWack = szEnumRootOutWack;
  349. copyParams.nCharsInRootOutWack = ByteCountA(szEnumRootOutWack);
  350. }
  351. else
  352. {
  353. copyParams.szEnumRootOutWack = NULL;
  354. copyParams.nCharsInRootOutWack = 0;
  355. }
  356. copyParams.pfnCallback = pfnCallback;
  357. copyParams.flags = flags;
  358. if ((flags & COPYTREE_DOCOPY) &&
  359. (flags & COPYTREE_DOMOVE))
  360. {
  361. return ERROR_INVALID_PARAMETER;
  362. }
  363. if (flags & COPYTREE_DODELETE) {
  364. AttributeFilter |= FILTER_DIRS_LAST;
  365. }
  366. return EnumerateTreeA(
  367. szEnumRootInWack,
  368. CopyFileCallbackA,
  369. pfnFailCallback,
  370. dwEnumHandle,
  371. (LPVOID)&copyParams,
  372. Levels,
  373. ExcludeInfStruct,
  374. AttributeFilter);
  375. }
  376. BOOL
  377. CopyTreeW(
  378. IN LPCWSTR szEnumRootIn,
  379. IN LPCWSTR szEnumRootOut,
  380. IN DWORD dwEnumHandle,
  381. IN DWORD flags,
  382. IN DWORD Levels,
  383. IN DWORD AttributeFilter,
  384. IN PEXCLUDEINFW ExcludeInfStruct, OPTIONAL
  385. IN FILEENUMPROCW pfnCallback, OPTIONAL
  386. IN FILEENUMFAILPROCW pfnFailCallback OPTIONAL
  387. )
  388. {
  389. COPYTREE_PARAMSW copyParams;
  390. WCHAR szEnumRootInWack[MAX_WCHAR_PATH];
  391. WCHAR szEnumRootOutWack[MAX_WCHAR_PATH];
  392. //
  393. // Place wacked copies of paths in parameter block.
  394. //
  395. //
  396. // Input Path
  397. //
  398. StringCopyTcharCountW(szEnumRootInWack, szEnumRootIn, ARRAYSIZE(szEnumRootInWack) - 1);
  399. AppendUncWackW(szEnumRootInWack);
  400. copyParams.szEnumRootInWack = szEnumRootInWack;
  401. copyParams.nCharsInRootInWack = wcslen(szEnumRootInWack);
  402. //
  403. // If output path is NULL, put 0 length and NULL ptr in param block.
  404. //
  405. if (NULL != szEnumRootOut)
  406. {
  407. StringCopyW(szEnumRootOutWack, szEnumRootOut);
  408. AppendUncWackW(szEnumRootOutWack);
  409. copyParams.szEnumRootOutWack = szEnumRootOutWack;
  410. copyParams.nCharsInRootOutWack = wcslen(szEnumRootOutWack);
  411. }
  412. else
  413. {
  414. copyParams.szEnumRootOutWack = NULL;
  415. copyParams.nCharsInRootOutWack = 0;
  416. }
  417. copyParams.pfnCallback = pfnCallback;
  418. copyParams.flags = flags;
  419. if ((flags & COPYTREE_DOCOPY) &&
  420. (flags & COPYTREE_DOMOVE))
  421. {
  422. return ERROR_INVALID_PARAMETER;
  423. }
  424. if (flags & COPYTREE_DODELETE) {
  425. AttributeFilter |= FILTER_DIRS_LAST;
  426. }
  427. return EnumerateTreeW(
  428. szEnumRootInWack,
  429. CopyFileCallbackW,
  430. pfnFailCallback,
  431. dwEnumHandle,
  432. (LPVOID)&copyParams,
  433. Levels,
  434. ExcludeInfStruct,
  435. AttributeFilter);
  436. }
  437. DWORD
  438. CreateEmptyDirectoryA (
  439. PCSTR Dir
  440. )
  441. {
  442. DWORD rc;
  443. if (!DeleteDirectoryContentsA (Dir)) {
  444. rc = GetLastError();
  445. if (rc != ERROR_PATH_NOT_FOUND)
  446. return rc;
  447. }
  448. if (!RemoveDirectoryA (Dir)) {
  449. rc = GetLastError();
  450. if (rc != ERROR_PATH_NOT_FOUND) {
  451. return rc;
  452. }
  453. }
  454. return MakeSurePathExistsA (Dir, TRUE);
  455. }
  456. DWORD
  457. CreateEmptyDirectoryW (
  458. PCWSTR Dir
  459. )
  460. {
  461. DWORD rc;
  462. if (!DeleteDirectoryContentsW (Dir)) {
  463. rc = GetLastError();
  464. if (rc != ERROR_PATH_NOT_FOUND)
  465. return rc;
  466. }
  467. if (!RemoveDirectoryW (Dir)) {
  468. rc = GetLastError();
  469. if (rc != ERROR_PATH_NOT_FOUND) {
  470. return rc;
  471. }
  472. }
  473. return MakeSurePathExistsW (Dir, TRUE);
  474. }
  475. #endif