Index: reactos/base/shell/cmd/copy.c =================================================================== --- reactos/base/shell/cmd/copy.c (revision 75745) +++ reactos/base/shell/cmd/copy.c (working copy) @@ -29,6 +29,10 @@ * 20-Jul-2005 (Brandon Turner ) * Add touch syntax. "copy arp.exe+,," * Copy command is now completed. + * + * 04-Sep-2017 (Doug Lyons ) + * Changed copy to use only 1 MB buffer repeatedly. + * This allows copying large files even with MM problems. */ #include "precomp.h" @@ -47,6 +51,36 @@ COPY_BINARY = 0x100, /* /B */ }; +/** +* @name GetFileSizeLocal +* +* Gets a files size even for large files +* +* @param fName +* const wchar_t File Name. +* +* @return +* The files size in bytes or -1 on Error. +* Handles file up to 4,294,967,294 bytes (2**32 - 1) in size. +*/ +long long GetFileSizeLocal(const wchar_t *fName) +{ + BOOL Ok; + WIN32_FILE_ATTRIBUTE_DATA fInfo; + + if (NULL == fName) + { + return (long long) -1; + } + + Ok = GetFileAttributesExW(fName, GetFileExInfoStandard, (void*)&fInfo); + if (!Ok) + { + return (long long) -1; + } + return (long long)fInfo.nFileSizeHigh * 0x100000000 + fInfo.nFileSizeLow; +} + INT copy(TCHAR source[MAX_PATH], TCHAR dest[MAX_PATH], @@ -57,15 +91,23 @@ FILETIME srctime,NewFileTime; HANDLE hFileSrc; HANDLE hFileDest; - LPBYTE buffer; +// LPBYTE buffer; DWORD dwAttrib; - DWORD dwRead; - DWORD dwWritten; - BOOL bEof = FALSE; +// DWORD dwRead; +// DWORD dwWritten; +// BOOL bEof = FALSE; TCHAR TrueDest[MAX_PATH]; TCHAR TempSrc[MAX_PATH]; TCHAR * FileName; SYSTEMTIME CurrentTime; + FILE *fptr1, *fptr2; // File Handles + long long pos = 0; // File Positions + long long rlen; // Record Length to read and write + long long sz1, sz2; // Size of files + long long bufsize = (1024 * 1024); // 1 MB Buffer size + char buf[bufsize]; // 1 Megabyte buffer + long long lenread; // bytes actually read + long long lenwrite; // bytes actually written /* Check Breaker */ if (CheckCtrlBreak(BREAK_INPUT)) @@ -200,7 +242,12 @@ return 0; } - /* A page-aligned buffer usually give more speed */ + +// Beginning of modified code to handle large file copies + +// This buffer is no longer used, so comment out code and leave for reference +/* + // A page-aligned buffer usually give more speed buffer = VirtualAlloc(NULL, BUFF_SIZE, MEM_COMMIT, PAGE_READWRITE); if (buffer == NULL) { @@ -210,7 +257,137 @@ nErrorLevel = 1; return 0; } +*/ +// Clean up previously opened files + if (hFileDest) + CloseHandle (hFileDest); + if (hFileSrc) + CloseHandle (hFileSrc); + + // Open first file for reading + fptr1 = _wfopen(source, L"rb, ccs=UNICODE"); + if (fptr1 == NULL) + { + printf("Cannot open file %S \n", source); +// Exit with first file error + nErrorLevel = 1; + return 0; + } + + fclose(fptr1); + + sz1 = GetFileSizeLocal(source); + if(sz1 == -1) + { + nErrorLevel = 1; + return 0; + } + + // Open second file for writing + fptr2 = _wfopen(dest, L"ab, ccs=UNICODE"); + if (fptr2 == NULL) + { + printf("Cannot open file %S \n", dest); +// Exit with second file error + nErrorLevel = 1; + return 0; + } + + fclose(fptr2); + +// Set up output line that we can backspace over + printf("Bytes Copied: %12I64d", (long long int) 0); + +// Start of loop + while (pos < sz1) + { + + // Open first file for reading + fptr1 = _wfopen(source, L"rb, ccs=UNICODE"); + + // Open second file for writing + fptr2 = _wfopen(dest, L"ab, ccs=UNICODE"); + + // get file #2 size which changes every loop + sz2 = GetFileSizeLocal(dest); + if(sz2 == -1) + { + nErrorLevel = 1; + return 0; + } + +// check if we need a full bufsize or less bytes to copy + if ((sz1 - sz2) > bufsize) + rlen = bufsize; + else + rlen = sz1 - sz2; + +// Set position of first file to read + fseek(fptr1, pos, SEEK_SET); + +// Read bytes + lenread = fread(buf, 1, rlen, fptr1); + +// Check for read errors and show error message and exit + if (lenread != rlen) + { + printf("Read Error Occurred. Copy not completed!\n"); + fclose(fptr1); + fclose(fptr2); +// Exit with first file error + nErrorLevel = 1; + return 0; + } + +// Set position of second file to write + fseek(fptr2, pos, SEEK_SET); + +// Write bytes + lenwrite = fwrite(buf, 1, lenread, fptr2); + +// Check for write errors and show error message and exit + if (lenread != lenwrite) + { + printf("Write Error Occurred. Copy not completed!\n"); + fclose(fptr1); + fclose(fptr2); +// Exit with second file error + nErrorLevel = 1; + return 0; + } + +// Close first file which is being read + fclose(fptr1); + +// Close second file which is being written + fclose(fptr2); + +// calculation the new file position where we are working + pos = pos + rlen; + +// Show progress on command line using same line without scrolling + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\bBytes Copied: %12I64d", pos); + +// End of loop here + } + +// Clear Bytes Copied Message + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + printf(" "); + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + + hFileDest = + CreateFile (dest, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + + TRACE ("setting time\n"); + SetFileTime (hFileDest, &srctime, NULL, NULL); + + CloseHandle (hFileDest); + +// End of modified code to handle large file copies + +/* // Previous code left here for reference do { ReadFile (hFileSrc, buffer, BUFF_SIZE, &dwRead, NULL); @@ -247,7 +424,7 @@ if ((lpdwFlags & COPY_ASCII) && !bEof) { - /* we're dealing with ASCII files! */ + // we're dealing with ASCII files! buffer[0] = 0x1A; TRACE ("appending ^Z\n"); WriteFile (hFileDest, buffer, sizeof(CHAR), &dwWritten, NULL); @@ -257,6 +434,8 @@ CloseHandle (hFileDest); CloseHandle (hFileSrc); +*/ // End of Previous Code Left + TRACE ("setting mode\n"); SetFileAttributes (dest, dwAttrib);