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.

350 lines
10 KiB

  1. //+============================================================================
  2. //
  3. // CopyFAPI.cxx
  4. //
  5. // This program provides a very simple wrapper of the CopyFileEx API
  6. // (and the PrivCopyFileEx in NT5) with no extra functionality.
  7. //
  8. //+============================================================================
  9. #define UNICODE
  10. #define _UNICODE
  11. #include <windows.h>
  12. #include <stdio.h>
  13. #include <process.h>
  14. #include <winbasep.h>
  15. //+----------------------------------------------------------------------------
  16. //
  17. // PromptForNotSupported
  18. //
  19. // When the PrivCopyFileEx callback function is called to inform the caller
  20. // that something couldn't be copied, this routine is used to prompt the
  21. // user of this utility to see if we should continue.
  22. //
  23. //+----------------------------------------------------------------------------
  24. struct
  25. {
  26. WCHAR wc;
  27. DWORD dwProgress;
  28. } rgPromptResponse[] = { {L'O', PROGRESS_CONTINUE},
  29. {L'A', PROGRESS_CANCEL},
  30. {L'S', PROGRESS_STOP},
  31. {L'Q', PROGRESS_QUIET},
  32. {L'N', PRIVPROGRESS_REASON_NOT_HANDLED} };
  33. DWORD
  34. PromptForNotSupported( LPWSTR pwszPrompt )
  35. {
  36. WCHAR wc = 'z';
  37. HANDLE hKeyboard = INVALID_HANDLE_VALUE;
  38. ULONG KeyboardModeNew, KeyboardModeOld;
  39. hKeyboard = CreateFile( (LPWSTR)L"CONIN$",
  40. GENERIC_READ | GENERIC_WRITE,
  41. FILE_SHARE_READ | FILE_SHARE_WRITE,
  42. NULL,
  43. OPEN_EXISTING,
  44. 0,
  45. NULL );
  46. if( INVALID_HANDLE_VALUE != hKeyboard
  47. &&
  48. !IsDebuggerPresent()
  49. &&
  50. GetConsoleMode( hKeyboard, &KeyboardModeOld ) )
  51. {
  52. KeyboardModeNew = KeyboardModeOld & ~(ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT);
  53. SetConsoleMode( hKeyboard, KeyboardModeNew );
  54. }
  55. while( TRUE )
  56. {
  57. for( int i = 0; i < sizeof(rgPromptResponse)/sizeof(rgPromptResponse[0]); i++ )
  58. {
  59. if( wc == rgPromptResponse[i].wc )
  60. return( rgPromptResponse[i].dwProgress );
  61. }
  62. wprintf( L"%s (cOntinue, cAncel, Stop, Quiet, Not handled) ", pwszPrompt );
  63. wc = getwchar();
  64. wprintf( L"\r" );
  65. wprintf( L" \r" );
  66. }
  67. SetConsoleMode( hKeyboard, KeyboardModeOld );
  68. CloseHandle( hKeyboard );
  69. return( PROGRESS_CONTINUE ); // Should never execute
  70. }
  71. //+----------------------------------------------------------------------------
  72. //
  73. // CopyFileProgressRoutine
  74. //
  75. // This is the callback function given to CopyFileEx (if so desired by
  76. // the user). It displays the progress information, and prompts the
  77. // user for permission to continue if something (e.g. ACLs) can't be
  78. // copied.
  79. //
  80. //+----------------------------------------------------------------------------
  81. DWORD
  82. WINAPI
  83. CopyFileProgressRoutine(
  84. LARGE_INTEGER TotalFileSize,
  85. LARGE_INTEGER TotalBytesTransferred,
  86. LARGE_INTEGER StreamSize,
  87. LARGE_INTEGER StreamBytesTransferred,
  88. DWORD dwStreamNumber,
  89. DWORD dwCallbackReason,
  90. HANDLE hSourceFile,
  91. HANDLE hDestinationFile,
  92. LPVOID lpData OPTIONAL
  93. )
  94. {
  95. wprintf( L"Progress: %7I64i, %7I64i, %7I64i, %7I64i, %7d\n",
  96. TotalFileSize.QuadPart, TotalBytesTransferred.QuadPart,
  97. StreamSize, StreamBytesTransferred,
  98. dwStreamNumber );
  99. switch( dwCallbackReason )
  100. {
  101. case PRIVCALLBACK_STREAMS_NOT_SUPPORTED:
  102. return( PromptForNotSupported( L"Streams not supported" ));
  103. case PRIVCALLBACK_SECURITY_INFORMATION_NOT_SUPPORTED:
  104. return( PromptForNotSupported( L"Security info not supported" ));
  105. case PRIVCALLBACK_COMPRESSION_NOT_SUPPORTED:
  106. return( PromptForNotSupported( L"Compression not supported" ));
  107. case PRIVCALLBACK_COMPRESSION_FAILED:
  108. return( PromptForNotSupported( L"Compression failed" ));
  109. case PRIVCALLBACK_ENCRYPTION_NOT_SUPPORTED:
  110. return( PromptForNotSupported( L"Encryption not supported" ));
  111. case PRIVCALLBACK_CANT_ENCRYPT_SYSTEM_FILE:
  112. return( PromptForNotSupported( L"Can't encrypt a system file" ));
  113. case PRIVCALLBACK_ENCRYPTION_FAILED:
  114. return( PromptForNotSupported( L"Encryption failed" ));
  115. case PRIVCALLBACK_EAS_NOT_SUPPORTED:
  116. return( PromptForNotSupported( L"EAs not supported" ));
  117. case PRIVCALLBACK_SPARSE_NOT_SUPPORTED:
  118. return( PromptForNotSupported( L"Sparse not supported" ));
  119. case PRIVCALLBACK_SPARSE_FAILED:
  120. return( PromptForNotSupported( L"Sparse failed" ));
  121. case PRIVCALLBACK_DACL_ACCESS_DENIED:
  122. return( PromptForNotSupported( L"DACL access denied" ));
  123. case PRIVCALLBACK_OWNER_GROUP_ACCESS_DENIED:
  124. return( PromptForNotSupported( L"Owner/group access denied" ));
  125. case PRIVCALLBACK_OWNER_GROUP_FAILED:
  126. return( PromptForNotSupported( L"Owner/group failed" ));
  127. case PRIVCALLBACK_SACL_ACCESS_DENIED:
  128. return( PromptForNotSupported( L"SACL access denied" ));
  129. case CALLBACK_CHUNK_FINISHED:
  130. case CALLBACK_STREAM_SWITCH:
  131. return( PROGRESS_CONTINUE );
  132. default:
  133. return( PromptForNotSupported( L"<Unknown>" ));
  134. }
  135. return( PRIVPROGRESS_REASON_NOT_HANDLED );
  136. }
  137. void
  138. Usage()
  139. {
  140. printf( "\n Purpose: Call the CopyFile API\n"
  141. " Usage: CopyFAPI [options] <source> <dest>\n"
  142. " Options: -f COPY_FILE_FAIL_IF_EXISTS\n"
  143. " -r COPY_FILE_RESTARTABLE\n"
  144. " -e COPY_FILE_ALLOW_DECRYPTED_DESTINATION\n"
  145. " -m PRIVCOPY_FILE_METADATA\n"
  146. " -s PRIVCOPY_FILE_SACL\n"
  147. " -u PRIVCOPY_FILE_SUPERSEDE\n"
  148. " -o PRIVCOPY_FILE_OWNER_GROUP\n"
  149. " -d PRIVCOPY_FILE_DIRECTORY\n"
  150. " -b PRIVCOPY_FILE_BACKUP_SEMANTICS\n"
  151. " -c Use the callback function\n"
  152. " Note: Since this simply calls the CopyFile API,\n"
  153. " you must specify the file path (not just\n"
  154. " the parent directory), and wildcards\n"
  155. " are not allowed\n" );
  156. }
  157. typedef BOOL (__stdcall *PFNMoveFileIdentityW)(
  158. LPCWSTR lpOldFileName,
  159. LPCWSTR lpNewFileName,
  160. DWORD dwFlags
  161. );
  162. typedef BOOL (__stdcall *PFNPrivCopyFileExW)(
  163. LPCWSTR lpExistingFileName,
  164. LPCWSTR lpNewFileName,
  165. LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL,
  166. LPVOID lpData OPTIONAL,
  167. LPBOOL pbCancel OPTIONAL,
  168. DWORD dwCopyFlags
  169. );
  170. //+----------------------------------------------------------------------------
  171. //
  172. // wmain
  173. //
  174. // User parameters are mapped to CopyFileEx parameters, then the API
  175. // is called.
  176. //
  177. //+----------------------------------------------------------------------------
  178. extern "C" void __cdecl
  179. wmain( int cArgs, WCHAR *rgpwszArgs[] )
  180. {
  181. LONG iArgs;
  182. DWORD dwCopyFileFlags = 0;
  183. BOOL fUseCallback = FALSE;
  184. cArgs--;
  185. iArgs = 1;
  186. while( cArgs > 0 )
  187. {
  188. if( L'-' != rgpwszArgs[iArgs][0]
  189. &&
  190. L'/' != rgpwszArgs[iArgs][0] )
  191. {
  192. break;
  193. }
  194. WCHAR wcUpper = towupper( rgpwszArgs[iArgs][1] );
  195. switch( wcUpper )
  196. {
  197. case 'F':
  198. dwCopyFileFlags |= COPY_FILE_FAIL_IF_EXISTS;
  199. break;
  200. case 'R':
  201. dwCopyFileFlags |= COPY_FILE_RESTARTABLE;
  202. break;
  203. case 'E':
  204. dwCopyFileFlags |= COPY_FILE_ALLOW_DECRYPTED_DESTINATION;
  205. break;
  206. case 'M':
  207. dwCopyFileFlags |= PRIVCOPY_FILE_METADATA;
  208. break;
  209. case 'S':
  210. dwCopyFileFlags |= PRIVCOPY_FILE_SACL;
  211. break;
  212. case 'U':
  213. dwCopyFileFlags |= PRIVCOPY_FILE_SUPERSEDE;
  214. break;
  215. case 'O':
  216. dwCopyFileFlags |= PRIVCOPY_FILE_OWNER_GROUP;
  217. break;
  218. case 'D':
  219. dwCopyFileFlags |= PRIVCOPY_FILE_DIRECTORY;
  220. break;
  221. case 'B':
  222. dwCopyFileFlags |= PRIVCOPY_FILE_BACKUP_SEMANTICS;
  223. break;
  224. case 'C':
  225. fUseCallback = TRUE;
  226. break;
  227. case 'X':
  228. dwCopyFileFlags |= 0x80;
  229. break;
  230. case 'P':
  231. dwCopyFileFlags |= 0x100;
  232. break;
  233. default:
  234. wprintf( L"Invalid option: %c\n", wcUpper );
  235. Usage();
  236. exit(0);
  237. }
  238. iArgs++;
  239. cArgs--;
  240. }
  241. if( cArgs != 2 )
  242. {
  243. Usage();
  244. exit(0);
  245. }
  246. if( fUseCallback )
  247. wprintf( L" cbTotal cbCur cbStm cbStmCur StmNum\n" );
  248. try
  249. {
  250. if( PRIVCOPY_FILE_VALID_FLAGS & dwCopyFileFlags )
  251. {
  252. // We need to call the private API
  253. PFNPrivCopyFileExW pfnPrivCopyFileExW;
  254. pfnPrivCopyFileExW = (PFNPrivCopyFileExW) GetProcAddress( GetModuleHandle(L"kernel32.dll"),
  255. "PrivCopyFileExW" );
  256. if( NULL == pfnPrivCopyFileExW )
  257. throw L"Couldn't get PrivCopyFileExW export";
  258. if( !pfnPrivCopyFileExW( rgpwszArgs[iArgs], rgpwszArgs[iArgs+1],
  259. fUseCallback ? CopyFileProgressRoutine : NULL,
  260. NULL, NULL, dwCopyFileFlags ))
  261. throw L"PrivCopyFileEx failed";
  262. else
  263. wprintf( L"Succeeded\n" );
  264. }
  265. else
  266. {
  267. // We can use the public API
  268. if( !CopyFileExW( rgpwszArgs[iArgs], rgpwszArgs[iArgs+1],
  269. fUseCallback ? CopyFileProgressRoutine : NULL,
  270. NULL, NULL, dwCopyFileFlags ))
  271. throw L"CopyFileEx failed";
  272. else
  273. wprintf( L"Succeeded\n" );
  274. }
  275. }
  276. catch( const WCHAR *pwszError )
  277. {
  278. wprintf( L"Error: %s (%lu)\n", pwszError, GetLastError() );
  279. }
  280. }