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.

499 lines
13 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. copy.c
  5. Abstract:
  6. This module implements the file copy command.
  7. Author:
  8. Wesley Witt (wesw) 21-Oct-1998
  9. Revision History:
  10. --*/
  11. #include "cmdcons.h"
  12. #pragma hdrstop
  13. BOOLEAN NoCopyPrompt;
  14. BOOLEAN AllowRemovableMedia;
  15. NTSTATUS
  16. pRcGetDeviceInfo(
  17. IN PWSTR FileName, // must be an nt name
  18. IN PFILE_FS_DEVICE_INFORMATION DeviceInfo
  19. )
  20. {
  21. BOOLEAN Removable = FALSE;
  22. IO_STATUS_BLOCK IoStatusBlock;
  23. UNICODE_STRING UnicodeString;
  24. HANDLE Handle;
  25. OBJECT_ATTRIBUTES Obja;
  26. NTSTATUS Status;
  27. PWSTR DeviceName;
  28. PWSTR s;
  29. //
  30. // get the device name from the file name
  31. //
  32. DeviceName = SpDupStringW( FileName );
  33. if (DeviceName == NULL) {
  34. return STATUS_OBJECT_PATH_INVALID;
  35. }
  36. s = wcschr(DeviceName+1,L'\\');
  37. if (!s) {
  38. return STATUS_OBJECT_PATH_INVALID;
  39. }
  40. s = wcschr(s+1,L'\\');
  41. if (s) {
  42. *s = 0;
  43. }
  44. INIT_OBJA(&Obja,&UnicodeString,DeviceName);
  45. Status = ZwCreateFile(
  46. &Handle,
  47. FILE_GENERIC_READ | SYNCHRONIZE,
  48. &Obja,
  49. &IoStatusBlock,
  50. NULL,
  51. FILE_ATTRIBUTE_NORMAL,
  52. FILE_SHARE_READ | FILE_SHARE_WRITE,
  53. FILE_OPEN,
  54. FILE_SYNCHRONOUS_IO_NONALERT,
  55. NULL,
  56. 0
  57. );
  58. SpMemFree(DeviceName);
  59. if(NT_SUCCESS(Status)) {
  60. Status = ZwQueryVolumeInformationFile(
  61. Handle,
  62. &IoStatusBlock,
  63. DeviceInfo,
  64. sizeof(FILE_FS_DEVICE_INFORMATION),
  65. FileFsDeviceInformation
  66. );
  67. ZwClose(Handle);
  68. }
  69. return Status;
  70. }
  71. NTSTATUS
  72. RcIsFileOnRemovableMedia(
  73. IN PWSTR FileName, // must be an nt name
  74. OUT PBOOLEAN Result
  75. )
  76. {
  77. NTSTATUS Status;
  78. FILE_FS_DEVICE_INFORMATION DeviceInfo;
  79. Status = pRcGetDeviceInfo( FileName, &DeviceInfo );
  80. *Result = NT_SUCCESS(Status) && (DeviceInfo.Characteristics & FILE_REMOVABLE_MEDIA) != 0;
  81. return Status;
  82. }
  83. NTSTATUS
  84. RcIsFileOnCDROM(
  85. IN PWSTR FileName // must be an nt name
  86. )
  87. {
  88. NTSTATUS Status;
  89. FILE_FS_DEVICE_INFORMATION DeviceInfo;
  90. Status = pRcGetDeviceInfo( FileName, &DeviceInfo );
  91. if(NT_SUCCESS(Status)) {
  92. if (DeviceInfo.DeviceType != FILE_DEVICE_CD_ROM) {
  93. Status = STATUS_NO_MEDIA;
  94. }
  95. }
  96. return Status;
  97. }
  98. NTSTATUS
  99. RcIsFileOnFloppy(
  100. IN PWSTR FileName // must be an nt name
  101. )
  102. {
  103. NTSTATUS Status;
  104. FILE_FS_DEVICE_INFORMATION DeviceInfo;
  105. Status = pRcGetDeviceInfo( FileName, &DeviceInfo );
  106. if(NT_SUCCESS(Status)) {
  107. if ((DeviceInfo.Characteristics & FILE_FLOPPY_DISKETTE) == 0) {
  108. Status = STATUS_NO_MEDIA;
  109. }
  110. }
  111. return Status;
  112. }
  113. BOOLEAN
  114. RcGetNTFileName(
  115. IN LPCWSTR DosPath,
  116. IN LPCWSTR NTPath
  117. )
  118. {
  119. BOOLEAN bResult = FALSE;
  120. extern LPWSTR _NtDrivePrefixes[26];
  121. WCHAR TempBuf[MAX_PATH*2];
  122. ULONG len;
  123. ULONG len2;
  124. LPWSTR Prefix;
  125. PWSTR s = NULL;
  126. Prefix = _NtDrivePrefixes[RcToUpper(DosPath[0])-L'A'];
  127. if (!Prefix) {
  128. return bResult;
  129. }
  130. GetDriveLetterLinkTarget((PWSTR)Prefix, &s);
  131. if (s) {
  132. len = wcslen(s);
  133. len2 = wcslen(DosPath) - 2;
  134. if (((len + len2) * sizeof(WCHAR)) < sizeof(TempBuf)){
  135. RtlZeroMemory(TempBuf,sizeof(TempBuf));
  136. RtlCopyMemory(TempBuf+len,DosPath+2,len2*sizeof(WCHAR));
  137. RtlCopyMemory(TempBuf,s,len*sizeof(WCHAR));
  138. TempBuf[len+len2] = 0;
  139. wcscpy((PWSTR)NTPath,TempBuf);
  140. bResult = TRUE;
  141. }
  142. }
  143. return bResult;
  144. }
  145. ULONG
  146. RcCmdCopy(
  147. IN PTOKENIZED_LINE TokenizedLine
  148. )
  149. {
  150. LPWSTR SrcFile;
  151. LPWSTR DstFile;
  152. LPWSTR SrcDosPath = NULL;
  153. LPWSTR SrcNtPath = NULL;
  154. LPWSTR DstDosPath = NULL;
  155. LPWSTR DstNtPath = NULL;
  156. IO_STATUS_BLOCK IoStatusBlock;
  157. UNICODE_STRING UnicodeString;
  158. HANDLE Handle;
  159. OBJECT_ATTRIBUTES Obja;
  160. NTSTATUS Status;
  161. LPWSTR YesNo;
  162. WCHAR Text[3];
  163. LPWSTR s;
  164. ULONG FileCount = 0;
  165. IO_STATUS_BLOCK status_block;
  166. FILE_BASIC_INFORMATION fileInfo;
  167. WCHAR * pos;
  168. ULONG CopyFlags = COPY_NOVERSIONCHECK;
  169. BOOLEAN OnRemovableMedia;
  170. ASSERT(TokenizedLine->TokenCount >= 1);
  171. if (RcCmdParseHelp( TokenizedLine, MSG_COPY_HELP )) {
  172. return 1;
  173. }
  174. //
  175. // create a good source & destination file name
  176. //
  177. if( TokenizedLine->TokenCount == 2 ) {
  178. SrcFile = TokenizedLine->Tokens->Next->String;
  179. DstFile = NULL;
  180. } else {
  181. SrcFile = TokenizedLine->Tokens->Next->String;
  182. DstFile = TokenizedLine->Tokens->Next->Next->String;
  183. }
  184. if (RcDoesPathHaveWildCards(SrcFile)) {
  185. RcMessageOut(MSG_DIR_WILDCARD_NOT_SUPPORTED);
  186. goto exit;
  187. }
  188. //
  189. // Canonicalize the name once to get a full DOS-style path
  190. // we can print out, and another time to get the NT-style path
  191. // we'll use to actually do the work.
  192. //
  193. if (!RcFormFullPath( SrcFile, _CmdConsBlock->TemporaryBuffer, FALSE )) {
  194. RcMessageOut(MSG_INVALID_PATH);
  195. return 1;
  196. }
  197. if (!RcIsPathNameAllowed(_CmdConsBlock->TemporaryBuffer,TRUE,FALSE)) {
  198. RcMessageOut(MSG_ACCESS_DENIED);
  199. goto exit;
  200. }
  201. SrcDosPath = SpDupStringW( _CmdConsBlock->TemporaryBuffer );
  202. if (!RcFormFullPath( SrcFile, _CmdConsBlock->TemporaryBuffer, TRUE )) {
  203. RcMessageOut(MSG_INVALID_PATH);
  204. return 1;
  205. }
  206. SrcNtPath = SpDupStringW( _CmdConsBlock->TemporaryBuffer );
  207. //
  208. // see if the source file exists
  209. //
  210. INIT_OBJA( &Obja, &UnicodeString, SrcNtPath );
  211. Status = ZwOpenFile(
  212. &Handle,
  213. FILE_READ_ATTRIBUTES,
  214. &Obja,
  215. &IoStatusBlock,
  216. FILE_SHARE_READ | FILE_SHARE_WRITE,
  217. 0
  218. );
  219. if( NT_SUCCESS(Status) ) {
  220. // check to see if the destination is a directory
  221. Status = ZwQueryInformationFile( Handle,
  222. &status_block,
  223. (PVOID)&fileInfo,
  224. sizeof( FILE_BASIC_INFORMATION ),
  225. FileBasicInformation );
  226. ZwClose( Handle );
  227. if( !NT_SUCCESS(Status) ) {
  228. // something went wrong
  229. RcNtError( Status, MSG_CANT_COPY_FILE );
  230. goto exit;
  231. }
  232. if( fileInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
  233. RcMessageOut(MSG_DIR_WILDCARD_NOT_SUPPORTED);
  234. goto exit;
  235. }
  236. } else {
  237. RcMessageOut(MSG_FILE_NOT_FOUND2);
  238. goto exit;
  239. }
  240. //
  241. // create a destination file name when the user did not
  242. // provide one. we use the source base file name and
  243. // the current drive and directory.
  244. //
  245. if ((DstFile == NULL) ||
  246. (wcscmp(DstFile, L".") == 0)) {
  247. s = wcsrchr( SrcDosPath, L'\\' );
  248. if( s ) {
  249. RcGetCurrentDriveAndDir( _CmdConsBlock->TemporaryBuffer );
  250. SpConcatenatePaths( _CmdConsBlock->TemporaryBuffer, s );
  251. DstFile = SpDupStringW( _CmdConsBlock->TemporaryBuffer );
  252. } else {
  253. RcMessageOut(MSG_INVALID_PATH);
  254. goto exit;
  255. }
  256. }
  257. //
  258. // create the destination paths
  259. //
  260. if (!RcFormFullPath( DstFile, _CmdConsBlock->TemporaryBuffer, FALSE )) {
  261. RcMessageOut(MSG_INVALID_PATH);
  262. return 1;
  263. }
  264. if (!RcIsPathNameAllowed(_CmdConsBlock->TemporaryBuffer,FALSE,FALSE)) {
  265. RcMessageOut(MSG_ACCESS_DENIED);
  266. goto exit;
  267. }
  268. DstDosPath = SpDupStringW( _CmdConsBlock->TemporaryBuffer );
  269. if (!RcFormFullPath( DstFile, _CmdConsBlock->TemporaryBuffer, TRUE )) {
  270. RcMessageOut(MSG_INVALID_PATH);
  271. return 1;
  272. }
  273. DstNtPath = SpDupStringW( _CmdConsBlock->TemporaryBuffer );
  274. //
  275. // check for removable media
  276. //
  277. Status = RcIsFileOnRemovableMedia(DstNtPath, &OnRemovableMedia);
  278. if (AllowRemovableMedia == FALSE && (!NT_SUCCESS(Status) || OnRemovableMedia)) {
  279. RcMessageOut(MSG_ACCESS_DENIED);
  280. goto exit;
  281. }
  282. //
  283. // see if the destination file already exists
  284. //
  285. INIT_OBJA( &Obja, &UnicodeString, DstNtPath );
  286. Status = ZwOpenFile(
  287. &Handle,
  288. FILE_READ_ATTRIBUTES,
  289. &Obja,
  290. &IoStatusBlock,
  291. FILE_SHARE_READ | FILE_SHARE_WRITE,
  292. 0
  293. );
  294. if( NT_SUCCESS(Status) ) {
  295. // the file exists!
  296. // check to see if the destination is a directory
  297. Status = ZwQueryInformationFile( Handle,
  298. &status_block,
  299. (PVOID)&fileInfo,
  300. sizeof( FILE_BASIC_INFORMATION ),
  301. FileBasicInformation );
  302. ZwClose( Handle );
  303. if( !NT_SUCCESS(Status) ) {
  304. // something went wrong
  305. RcNtError( Status, MSG_CANT_COPY_FILE );
  306. goto exit;
  307. }
  308. if( fileInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
  309. // yep, it's a directory
  310. // take the fully qualified source file path
  311. // and get the file name from it by finding the
  312. // last occurance of the \\ character
  313. pos = wcsrchr( SrcNtPath, L'\\' );
  314. SpMemFree( (PVOID)DstNtPath );
  315. // append the file name to the directory so that the copy
  316. // will work properly.
  317. if( pos != NULL ) {
  318. wcscat( _CmdConsBlock->TemporaryBuffer, pos );
  319. } else {
  320. wcscat( _CmdConsBlock->TemporaryBuffer, SrcNtPath );
  321. }
  322. DstNtPath = SpDupStringW( _CmdConsBlock->TemporaryBuffer );
  323. // now check again for the file's existence
  324. INIT_OBJA( &Obja, &UnicodeString, DstNtPath );
  325. Status = ZwOpenFile(
  326. &Handle,
  327. FILE_READ_ATTRIBUTES,
  328. &Obja,
  329. &IoStatusBlock,
  330. FILE_SHARE_READ | FILE_SHARE_WRITE,
  331. 0
  332. );
  333. if( NT_SUCCESS(Status) ) {
  334. ZwClose( Handle );
  335. //
  336. // Fetch yes/no text
  337. //
  338. if (InBatchMode == FALSE && NoCopyPrompt == FALSE) {
  339. YesNo = SpRetreiveMessageText( ImageBase, MSG_YESNOALL, NULL, 0 );
  340. if( YesNo ) {
  341. s = wcsrchr( DstNtPath, L'\\' );
  342. RcMessageOut( MSG_COPY_OVERWRITE, s ? s+1 : DstNtPath );
  343. if( RcLineIn( Text, 2 ) ) {
  344. if( (Text[0] == YesNo[0]) || (Text[0] == YesNo[1]) ) {
  345. goto exit;
  346. }
  347. } else {
  348. goto exit;
  349. }
  350. SpMemFree( YesNo );
  351. }
  352. }
  353. }
  354. } else {
  355. //
  356. // If destination file was not compressed, copy it uncompressed.
  357. //
  358. if(!(fileInfo.FileAttributes & FILE_ATTRIBUTE_COMPRESSED)) {
  359. CopyFlags |= COPY_FORCENOCOMP;
  360. }
  361. // nope the dest wasn't a dir, ask if we should overwrite
  362. //
  363. // Fetch yes/no text
  364. //
  365. if (InBatchMode == FALSE && NoCopyPrompt == FALSE) {
  366. YesNo = SpRetreiveMessageText( ImageBase, MSG_YESNOALL, NULL, 0 );
  367. if( YesNo ) {
  368. s = wcsrchr( DstNtPath, L'\\' );
  369. RcMessageOut( MSG_COPY_OVERWRITE, s ? s+1 : DstNtPath );
  370. if( RcLineIn( Text, 2 ) ) {
  371. if( (Text[0] == YesNo[0]) || (Text[0] == YesNo[1]) ) {
  372. goto exit;
  373. }
  374. } else {
  375. goto exit;
  376. }
  377. SpMemFree( YesNo );
  378. }
  379. }
  380. }
  381. }
  382. Status = SpCopyFileUsingNames( SrcNtPath, DstNtPath, 0, CopyFlags );
  383. if( NT_SUCCESS(Status) ) {
  384. FileCount += 1;
  385. } else {
  386. RcNtError( Status, MSG_CANT_COPY_FILE );
  387. }
  388. if( FileCount ) {
  389. RcMessageOut( MSG_COPY_COUNT, FileCount );
  390. }
  391. exit:
  392. if( DstFile && TokenizedLine->TokenCount == 2 ) {
  393. SpMemFree( DstFile );
  394. }
  395. if( SrcDosPath ) {
  396. SpMemFree( SrcDosPath );
  397. }
  398. if( SrcNtPath ) {
  399. SpMemFree( SrcNtPath );
  400. }
  401. if( DstDosPath ) {
  402. SpMemFree( DstDosPath );
  403. }
  404. if( DstNtPath ) {
  405. SpMemFree( DstNtPath );
  406. }
  407. return 1;
  408. }