Source code of Windows XP (NT5)
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.

697 lines
21 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. copy.c
  5. Abstract:
  6. This module contains the routine to copy a file.
  7. Author:
  8. David Treadwell (davidtr) 24-Jan-1990
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #include "copy.tmh"
  13. #pragma hdrstop
  14. #define BugCheckFileId SRV_FILE_COPY
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text( PAGE, SrvCopyFile )
  17. #endif
  18. #define EOF 0x1A // Control-Z == end of file
  19. NTSTATUS
  20. SrvCopyFile (
  21. IN HANDLE SourceHandle,
  22. IN HANDLE TargetHandle,
  23. IN USHORT SmbOpenFunction,
  24. IN USHORT SmbFlags,
  25. IN ULONG ActionTaken
  26. )
  27. /*++
  28. Routine Description:
  29. This routine copies or appends from the source file to the target file.
  30. It does the following:
  31. read sources EAs, attributes, size
  32. create/open target using source's info
  33. read data from source and write it to target
  34. Arguments:
  35. SourceHandle - handle to source file opened with SRV_COPY_SOURCE_ACCESS
  36. for synchronous access.
  37. TargetHandle - handle to target file opened with SRV_COPY_SOURCE_ACCESS
  38. for synchronous access.
  39. SmbOpenFunction - used to determine whether the source should be
  40. appended to the end of the target.
  41. ActionTaken - Information field of IO status block from the NtCreateFile
  42. where the target was opened. This is used to determine whether
  43. the target should be deleted if an error occurs.
  44. Return Value:
  45. NTSTATUS - STATUS_SUCCESS or error.
  46. --*/
  47. {
  48. NTSTATUS status;
  49. NTSTATUS readStatus = STATUS_SUCCESS;
  50. NTSTATUS writeStatus = STATUS_SUCCESS;
  51. IO_STATUS_BLOCK ioStatusBlock;
  52. FILE_EA_INFORMATION eaInfo;
  53. SRV_NETWORK_OPEN_INFORMATION sourceNetworkOpenInformation;
  54. SRV_NETWORK_OPEN_INFORMATION targetNetworkOpenInformation;
  55. FILE_POSITION_INFORMATION positionInfo;
  56. FILE_ALLOCATION_INFORMATION allocationInfo;
  57. LARGE_INTEGER fileOffset;
  58. BOOLEAN append;
  59. BOOLEAN sourceIsAscii;
  60. BOOLEAN targetIsAscii;
  61. PCHAR ioBuffer;
  62. ULONG ioBufferSize;
  63. ULONG offset = 0;
  64. ULONG bytesRead;
  65. BOOLEAN eofFound = FALSE;
  66. CHAR lastByte;
  67. PAGED_CODE( );
  68. //
  69. // Find out if we are supposed to append to the target file or
  70. // overwrite it, and whether this is a binary or ASCII copy for
  71. // the source and target. In a binary copy for the source, we stop
  72. // the first time we see EOF (control-Z). In a binary copy for the
  73. // target, we must make sure that there is exactly one EOF in the
  74. // file and that this is the last character of the file.
  75. //
  76. append = SmbOfunAppend( SmbOpenFunction );
  77. sourceIsAscii = (BOOLEAN)((SmbFlags & SMB_COPY_SOURCE_ASCII) != 0);
  78. targetIsAscii = (BOOLEAN)((SmbFlags & SMB_COPY_TARGET_ASCII) != 0);
  79. //
  80. // Find the size of the EAs on the source.
  81. //
  82. status = NtQueryInformationFile(
  83. SourceHandle,
  84. &ioStatusBlock,
  85. &eaInfo,
  86. sizeof(eaInfo),
  87. FileEaInformation
  88. );
  89. if ( !NT_SUCCESS(status) ) {
  90. INTERNAL_ERROR(
  91. ERROR_LEVEL_UNEXPECTED,
  92. "SrvCopyFile: NtQueryInformationFile (source EA size) failed: %X",
  93. status,
  94. NULL
  95. );
  96. SrvLogServiceFailure( SRV_SVC_NT_QUERY_INFO_FILE, status );
  97. return status;
  98. }
  99. //
  100. // If the source file has EAs, get them and write them to the target
  101. // file.
  102. //
  103. if ( eaInfo.EaSize > 0 ) {
  104. PCHAR eaBuffer;
  105. ULONG eaBufferSize;
  106. //
  107. // Allocate a buffer large enough to hold the EAs.
  108. //
  109. //
  110. // HACKHACK: eaInfo.EaSize is the size needed by OS/2. For NT,
  111. // the system has no way of telling us how big a buffer we need.
  112. // According to BrianAn, this should not be bigger than twice
  113. // what OS/2 needs.
  114. //
  115. eaBufferSize = eaInfo.EaSize * EA_SIZE_FUDGE_FACTOR;
  116. eaBuffer = ALLOCATE_NONPAGED_POOL( eaBufferSize, BlockTypeDataBuffer );
  117. if ( eaBuffer == NULL ) {
  118. INTERNAL_ERROR(
  119. ERROR_LEVEL_EXPECTED,
  120. "SrvCopyFile: Unable to allocate %d bytes nonpaged pool",
  121. eaBufferSize,
  122. NULL
  123. );
  124. return STATUS_INSUFF_SERVER_RESOURCES;
  125. }
  126. status = SrvIssueQueryEaRequest(
  127. SourceHandle,
  128. eaBuffer,
  129. eaBufferSize,
  130. NULL,
  131. 0L,
  132. FALSE,
  133. NULL
  134. );
  135. if ( NT_SUCCESS(status) ) {
  136. status = ioStatusBlock.Status;
  137. }
  138. if ( !NT_SUCCESS(status) ) {
  139. INTERNAL_ERROR(
  140. ERROR_LEVEL_UNEXPECTED,
  141. "SrvCopyFile: SrvIssueQueryEaRequest failed: %X",
  142. status,
  143. NULL
  144. );
  145. SrvLogServiceFailure( SRV_SVC_NT_QUERY_EAS, status );
  146. DEALLOCATE_NONPAGED_POOL( eaBuffer );
  147. return status;
  148. }
  149. status = SrvIssueSetEaRequest(
  150. TargetHandle,
  151. eaBuffer,
  152. eaBufferSize,
  153. NULL
  154. );
  155. if ( NT_SUCCESS(status) ) {
  156. status = ioStatusBlock.Status;
  157. }
  158. if ( status == STATUS_EAS_NOT_SUPPORTED ||
  159. status == STATUS_NOT_IMPLEMENTED ) {
  160. if ( SrvAreEasNeeded( (PFILE_FULL_EA_INFORMATION)eaBuffer ) ) {
  161. DEALLOCATE_NONPAGED_POOL( eaBuffer );
  162. return STATUS_EAS_NOT_SUPPORTED;
  163. }
  164. status = STATUS_SUCCESS;
  165. }
  166. DEALLOCATE_NONPAGED_POOL( eaBuffer );
  167. if ( !NT_SUCCESS(status) ) {
  168. INTERNAL_ERROR(
  169. ERROR_LEVEL_UNEXPECTED,
  170. "SrvCopyFile: SrvIssueSetEaRequest failed: %X",
  171. status,
  172. NULL
  173. );
  174. SrvLogServiceFailure( SRV_SVC_NT_SET_EAS, status );
  175. return status;
  176. }
  177. }
  178. //
  179. // Get the various attributes of the source file--size, times, etc.
  180. // These are used later on to set attributes of the target file.
  181. //
  182. status = SrvQueryNetworkOpenInformation(
  183. SourceHandle,
  184. NULL,
  185. &sourceNetworkOpenInformation,
  186. FALSE
  187. );
  188. if ( !NT_SUCCESS(status) ) {
  189. INTERNAL_ERROR(
  190. ERROR_LEVEL_UNEXPECTED,
  191. "SrvCopyFile: NtQueryInformationFile "
  192. "returned %X",
  193. status,
  194. NULL
  195. );
  196. SrvLogServiceFailure( SRV_SVC_NT_QUERY_INFO_FILE, status );
  197. return status;
  198. }
  199. //
  200. // If target was opened and we're in append mode, save the target's
  201. // original size and time and set target file pointer to the end of
  202. // the file.
  203. //
  204. if ( append ) {
  205. status = SrvQueryNetworkOpenInformation(
  206. TargetHandle,
  207. NULL,
  208. &targetNetworkOpenInformation,
  209. FALSE
  210. );
  211. if ( !NT_SUCCESS(status) ) {
  212. INTERNAL_ERROR(
  213. ERROR_LEVEL_UNEXPECTED,
  214. "SrvCopyFile: NtQueryInformationFile "
  215. "for target returned %X",
  216. status,
  217. NULL
  218. );
  219. SrvLogServiceFailure( SRV_SVC_NT_QUERY_INFO_FILE, status );
  220. return status;
  221. }
  222. //
  223. // If the target is in ASCII mode, then see if the last character
  224. // of the target file is EOF (^Z). If so, then set EndOfFile
  225. // such that this character will be overwritten.
  226. //
  227. if ( targetIsAscii && (targetNetworkOpenInformation.EndOfFile.QuadPart > 0) ) {
  228. LARGE_INTEGER fileOffset;
  229. fileOffset.QuadPart = targetNetworkOpenInformation.EndOfFile.QuadPart - 1;
  230. status = NtReadFile(
  231. TargetHandle,
  232. NULL,
  233. NULL,
  234. NULL,
  235. &ioStatusBlock,
  236. &lastByte,
  237. sizeof(lastByte),
  238. &fileOffset,
  239. NULL
  240. );
  241. if ( !NT_SUCCESS(status) ) {
  242. INTERNAL_ERROR(
  243. ERROR_LEVEL_UNEXPECTED,
  244. "SrvCopyFile: NtReadFile for target last byte"
  245. "returned %X",
  246. status,
  247. NULL
  248. );
  249. SrvLogServiceFailure( SRV_SVC_NT_READ_FILE, status );
  250. return status;
  251. }
  252. if ( lastByte == EOF ) {
  253. targetNetworkOpenInformation.EndOfFile = fileOffset;
  254. }
  255. }
  256. positionInfo.CurrentByteOffset = targetNetworkOpenInformation.EndOfFile;
  257. status = NtSetInformationFile(
  258. TargetHandle,
  259. &ioStatusBlock,
  260. &positionInfo,
  261. sizeof(positionInfo),
  262. FilePositionInformation
  263. );
  264. if ( !NT_SUCCESS(status) ) {
  265. INTERNAL_ERROR(
  266. ERROR_LEVEL_UNEXPECTED,
  267. "SrvCopyFile: NtSetInformationFile(position information)"
  268. "for target returned %X",
  269. status,
  270. NULL
  271. );
  272. SrvLogServiceFailure( SRV_SVC_NT_SET_INFO_FILE, status );
  273. return status;
  274. }
  275. }
  276. //
  277. // Set the new size of the output file. Doing this avoids forcing
  278. // the file system to automatically extend the file bit by bit.
  279. //
  280. if ( append ) {
  281. allocationInfo.AllocationSize.QuadPart =
  282. targetNetworkOpenInformation.EndOfFile.QuadPart +
  283. sourceNetworkOpenInformation.EndOfFile.QuadPart;
  284. } else {
  285. allocationInfo.AllocationSize = sourceNetworkOpenInformation.EndOfFile;
  286. }
  287. if ( 0 ) {
  288. KdPrint(( "SrvCopyFile: Setting allocation size of target to "
  289. "%ld (0x%lx) bytes\n",
  290. allocationInfo.AllocationSize.LowPart,
  291. allocationInfo.AllocationSize.LowPart
  292. ));
  293. KdPrint(( " %ld (0x%lx) blocks + %ld (0x%lx) bytes\n",
  294. allocationInfo.AllocationSize.LowPart / 512,
  295. allocationInfo.AllocationSize.LowPart / 512,
  296. allocationInfo.AllocationSize.LowPart % 512,
  297. allocationInfo.AllocationSize.LowPart % 512
  298. ));
  299. }
  300. status = NtSetInformationFile(
  301. TargetHandle,
  302. &ioStatusBlock,
  303. &allocationInfo,
  304. sizeof(allocationInfo),
  305. FileAllocationInformation
  306. );
  307. if ( !NT_SUCCESS(status) ) {
  308. INTERNAL_ERROR(
  309. ERROR_LEVEL_UNEXPECTED,
  310. "SrvCopyFile: NtSetInformationFile(allocation information)"
  311. "for target returned %X",
  312. status,
  313. NULL
  314. );
  315. SrvLogServiceFailure( SRV_SVC_NT_SET_INFO_FILE, status );
  316. return status;
  317. }
  318. //
  319. // Allocate a buffer from server heap to use for the data copy.
  320. //
  321. ioBufferSize = 4096;
  322. ioBuffer = ALLOCATE_HEAP_COLD( ioBufferSize, BlockTypeDataBuffer );
  323. if ( ioBuffer == NULL ) {
  324. INTERNAL_ERROR(
  325. ERROR_LEVEL_EXPECTED,
  326. "SrvCopyFile: Unable to allocate %d bytes from heap.",
  327. ioBufferSize,
  328. NULL
  329. );
  330. return STATUS_INSUFF_SERVER_RESOURCES;
  331. }
  332. //
  333. // Copy data--read from source, write to target. Do this until
  334. // all the data is written or an error occurs.
  335. //
  336. fileOffset.QuadPart = (LONG)FILE_USE_FILE_POINTER_POSITION;
  337. while ( !eofFound ) {
  338. if ( 0 ) {
  339. KdPrint(( "SrvCopyFile: reading %ld (0x%lx) bytes at "
  340. "offset %ld (0x%lx)\n",
  341. ioBufferSize, ioBufferSize, offset, offset ));
  342. }
  343. readStatus = NtReadFile(
  344. SourceHandle,
  345. NULL, // Event
  346. NULL, // ApcRoutine
  347. NULL, // ApcContext
  348. &ioStatusBlock,
  349. ioBuffer,
  350. ioBufferSize,
  351. &fileOffset,
  352. NULL // Key
  353. );
  354. if ( !NT_SUCCESS(readStatus) && readStatus != STATUS_END_OF_FILE ) {
  355. INTERNAL_ERROR(
  356. ERROR_LEVEL_UNEXPECTED,
  357. "SrvCopyFile: NtReadFile returned %X",
  358. readStatus,
  359. NULL
  360. );
  361. FREE_HEAP( ioBuffer );
  362. SrvLogServiceFailure( SRV_SVC_NT_READ_FILE, readStatus );
  363. return readStatus;
  364. }
  365. IF_SMB_DEBUG(FILE_CONTROL2) {
  366. KdPrint(( "NtReadFile: Read %p bytes from source file\n",
  367. (PVOID)ioStatusBlock.Information ));
  368. }
  369. if ( ioStatusBlock.Information == 0 ||
  370. readStatus == STATUS_END_OF_FILE ) {
  371. break;
  372. }
  373. bytesRead = (ULONG)ioStatusBlock.Information;
  374. if ( 0 ) {
  375. IO_STATUS_BLOCK iosb;
  376. status = NtQueryInformationFile(
  377. SourceHandle,
  378. &iosb,
  379. &positionInfo,
  380. sizeof(positionInfo),
  381. FilePositionInformation
  382. );
  383. if ( !NT_SUCCESS( status ) ) {
  384. INTERNAL_ERROR(
  385. ERROR_LEVEL_UNEXPECTED,
  386. "SrvCopyFile: NtQueryInformationFile returned %X",
  387. status,
  388. NULL
  389. );
  390. FREE_HEAP( ioBuffer );
  391. SrvLogServiceFailure( SRV_SVC_NT_QUERY_INFO_FILE, status );
  392. return status;
  393. }
  394. if ( positionInfo.CurrentByteOffset.LowPart !=
  395. offset + bytesRead ) {
  396. KdPrint(( "SrvCopyFile: SOURCE FILE POSITION NOT PROPERLY "
  397. "UPDATED!!!\n" ));
  398. KdPrint(( " expected %ld + %ld = %ld (0x%lx); ",
  399. offset, bytesRead,
  400. offset + bytesRead, offset + bytesRead ));
  401. KdPrint(( "got %ld (0x%lx)\n",
  402. positionInfo.CurrentByteOffset.LowPart,
  403. positionInfo.CurrentByteOffset.LowPart ));
  404. }
  405. KdPrint(( "SrvCopyFile: writing 0x%p bytes at offset %ld (0x%lx)\n",
  406. (PVOID)ioStatusBlock.Information,
  407. offset, offset ));
  408. }
  409. //
  410. // If the source file is in ASCII mode, then search for EOF in the
  411. // buffer. We copy until we hit the first EOF, at which point
  412. // we quit.
  413. //
  414. if ( sourceIsAscii ) {
  415. ULONG i;
  416. for ( i = 0; i < bytesRead; i++ ) {
  417. if ( ((PCHAR)ioBuffer)[i] == EOF ) {
  418. bytesRead = i + 1;
  419. eofFound = TRUE;
  420. break;
  421. }
  422. }
  423. }
  424. //
  425. // Save the last byte read. This is useful to make sure that
  426. // there is an EOF character if the target file is ASCII.
  427. //
  428. lastByte = ((PCHAR)ioBuffer)[bytesRead-1];
  429. writeStatus = NtWriteFile(
  430. TargetHandle,
  431. NULL, // Event
  432. NULL, // ApcRoutine
  433. NULL, // ApcContext
  434. &ioStatusBlock,
  435. ioBuffer,
  436. bytesRead,
  437. &fileOffset,
  438. NULL // Key
  439. );
  440. if ( !NT_SUCCESS(writeStatus) ) {
  441. INTERNAL_ERROR(
  442. ERROR_LEVEL_UNEXPECTED,
  443. "SrvCopyFile: NtWriteFile returned %X",
  444. writeStatus,
  445. NULL
  446. );
  447. FREE_HEAP( ioBuffer );
  448. SrvLogServiceFailure( SRV_SVC_NT_WRITE_FILE, writeStatus );
  449. return writeStatus;
  450. }
  451. IF_SMB_DEBUG(FILE_CONTROL2) {
  452. KdPrint(( "NtWriteFile: wrote %p bytes to target file\n",
  453. (PVOID)ioStatusBlock.Information ));
  454. }
  455. if ( 0 ) {
  456. IO_STATUS_BLOCK iosb;
  457. if ( ioStatusBlock.Information != bytesRead ) {
  458. KdPrint(( "SrvCopyFile: WRITE COUNT MISMATCH!!!\n" ));
  459. KdPrint(( " Bytes read: %ld (0x%lx); Bytes written: 0x%p \n",
  460. bytesRead, bytesRead,
  461. (PVOID)ioStatusBlock.Information ));
  462. }
  463. status = NtQueryInformationFile(
  464. SourceHandle,
  465. &iosb,
  466. &positionInfo,
  467. sizeof(positionInfo),
  468. FilePositionInformation
  469. );
  470. if ( !NT_SUCCESS( status ) ) {
  471. INTERNAL_ERROR(
  472. ERROR_LEVEL_UNEXPECTED,
  473. "SrvCopyFile: NtQueryInformationFile returned %X",
  474. status,
  475. NULL
  476. );
  477. FREE_HEAP( ioBuffer );
  478. SrvLogServiceFailure( SRV_SVC_NT_QUERY_INFO_FILE, status );
  479. return status;
  480. }
  481. if ( positionInfo.CurrentByteOffset.LowPart !=
  482. offset + ioStatusBlock.Information ) {
  483. KdPrint(( "SrvCopyFile: TARGET FILE POSITION NOT PROPERLY "
  484. "UPDATED!!!\n" ));
  485. KdPrint(( " expected 0x%lx + 0x%p = 0x%p; ",
  486. offset, (PVOID)(ioStatusBlock.Information),
  487. (PVOID)(offset + ioStatusBlock.Information) ));
  488. KdPrint(( "got %ld (0x%lx)\n",
  489. positionInfo.CurrentByteOffset.LowPart,
  490. positionInfo.CurrentByteOffset.LowPart ));
  491. }
  492. }
  493. offset += bytesRead;
  494. }
  495. FREE_HEAP( ioBuffer );
  496. //
  497. // If target was created or replaced, set its time to that of the source.
  498. //
  499. if ( ActionTaken == FILE_CREATED || ActionTaken == FILE_SUPERSEDED ) {
  500. FILE_BASIC_INFORMATION basicInfo;
  501. basicInfo.CreationTime = sourceNetworkOpenInformation.CreationTime;
  502. basicInfo.LastAccessTime = sourceNetworkOpenInformation.LastAccessTime;
  503. basicInfo.LastWriteTime = sourceNetworkOpenInformation.LastWriteTime;
  504. basicInfo.ChangeTime = sourceNetworkOpenInformation.ChangeTime;
  505. basicInfo.FileAttributes = sourceNetworkOpenInformation.FileAttributes;
  506. status = NtSetInformationFile(
  507. TargetHandle,
  508. &ioStatusBlock,
  509. &basicInfo,
  510. sizeof(basicInfo),
  511. FileBasicInformation
  512. );
  513. if ( !NT_SUCCESS(status) ) {
  514. INTERNAL_ERROR(
  515. ERROR_LEVEL_UNEXPECTED,
  516. "SrvCopyFile: NtSetInformationFile(basic information) for"
  517. "target returned %X",
  518. status,
  519. NULL
  520. );
  521. SrvLogServiceFailure( SRV_SVC_NT_SET_INFO_FILE, status );
  522. return status;
  523. }
  524. }
  525. //
  526. // If the target is ASCII and the last byte was not an EOF, then
  527. // put on an EOF character.
  528. //
  529. if ( targetIsAscii && lastByte != EOF ) {
  530. lastByte = EOF;
  531. status = NtWriteFile(
  532. TargetHandle,
  533. NULL,
  534. NULL,
  535. NULL,
  536. &ioStatusBlock,
  537. &lastByte,
  538. sizeof(lastByte),
  539. NULL,
  540. NULL
  541. );
  542. if ( !NT_SUCCESS(status) ) {
  543. INTERNAL_ERROR(
  544. ERROR_LEVEL_UNEXPECTED,
  545. "SrvCopyFile: NtWriteFile returned %X",
  546. status,
  547. NULL
  548. );
  549. SrvLogServiceFailure( SRV_SVC_NT_WRITE_FILE, status );
  550. return status;
  551. }
  552. }
  553. return STATUS_SUCCESS;
  554. } // SrvCopyFile