| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105 |
- /*
- ** Command & Conquer Renegade(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /***********************************************************************************************
- *** Confidential - Westwood Studios ***
- ***********************************************************************************************
- * *
- * Project Name : Installer *
- * *
- * $Archive:: /Commando/Code/Installer/CopyThread.cpp $*
- * *
- * $Author:: Ian_l $*
- * *
- * $Modtime:: 1/13/02 5:00p $*
- * *
- * $Revision:: 10 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- // Includes.
- #include "CopyThread.h"
- #include "ErrorHandler.h"
- #include "FDI.h"
- #include "Installer.h"
- #include "RegistryManager.h"
- #include "Resource.h"
- #include "Translator.h"
- #include "Verchk.h"
- #include <io.h>
- #include <fcntl.h>
- #include <sys/stat.h>
- #include <share.h>
- // Defines.
- #define COPY_MESSAGE_FORMAT_STRING L"%s %s"
- // Static data.
- CopyThreadClass *CopyThreadClass::_ActiveCopyThread = NULL;
- /***************************************************************************
- * Memory allocation function
- * HUGE * FAR DIAMONDAPI fdi_mem_alloc( ULONG cb )
- *=========================================================================*/
- FNALLOC( fdi_mem_alloc )
- {
- return (malloc (cb));
- }
- /***************************************************************************
- * Memory free function
- * FAR DIAMONDAPI fdi_mem_free( void HUGE *pv )
- *=========================================================================*/
- FNFREE( fdi_mem_free )
- {
- free (pv);
- }
- /***************************************************************************
- * int FAR DIAMONDAPI file_open( char FAR *pszFile, int oflag, int pmode )
- *=========================================================================*/
- FNOPEN( file_open )
- {
- HANDLE handle;
- WWASSERT ((oflag & (_O_APPEND | _O_TEMPORARY)) == 0x0);
-
- DWORD desiredaccess, creationdisposition, flagsandattributes;
- if (oflag & _O_WRONLY) {
- desiredaccess = GENERIC_WRITE;
- } else {
- if (oflag & _O_RDWR) {
- desiredaccess = GENERIC_READ | GENERIC_WRITE;
- } else {
- desiredaccess = GENERIC_READ;
- }
- }
- if (oflag & (_O_CREAT | _O_TRUNC)) {
- creationdisposition = OPEN_ALWAYS;
- } else {
- if (oflag & _O_CREAT) {
- creationdisposition = CREATE_NEW;
- } else {
- if (oflag & _O_TRUNC) {
- creationdisposition = TRUNCATE_EXISTING;
- } else {
- creationdisposition = OPEN_EXISTING;
- }
- }
- }
- if (pmode & _S_IREAD) {
- flagsandattributes = FILE_ATTRIBUTE_READONLY;
- } else {
- flagsandattributes = FILE_ATTRIBUTE_NORMAL;
- }
- while ((handle = CreateFile (pszFile, desiredaccess, FILE_SHARE_READ, NULL, creationdisposition, flagsandattributes | FILE_FLAG_WRITE_THROUGH, NULL)) == INVALID_HANDLE_VALUE) {
- if (!CopyThreadClass::_ActiveCopyThread->Retry()) break;
- }
- return ((int) handle);
- }
- /***************************************************************************
- * UINT FAR DIAMONDAPI file_read( int hf, void FAR *pv, UINT cb )
- *=========================================================================*/
- FNREAD( file_read )
- {
- // Abort the copying process?
- if (!CopyThreadClass::_ActiveCopyThread->Get_Abort (true)) {
- unsigned long bytecount;
-
- while (!ReadFile ((void*) hf, pv, cb, &bytecount, NULL)) {
- if (!CopyThreadClass::_ActiveCopyThread->Retry()) break;
- }
- return (bytecount);
- } else {
-
- // NOTE: Returning -1 will cause the calling cabinet process to close all
- // files, release its resources, and return an error code to the caller of
- // FDICopy().
- return (-1);
- }
- }
- /***************************************************************************
- * UINT FAR DIAMONDAPI file_write( int hf, void FAR *pv, UINT cb )
- *=========================================================================*/
- FNWRITE( file_write )
- {
- // Abort the copying process?
- if (!CopyThreadClass::_ActiveCopyThread->Get_Abort (true)) {
- unsigned long bytecount;
-
- while (!WriteFile ((void*) hf, pv, cb, &bytecount, NULL)) {
- if (!CopyThreadClass::_ActiveCopyThread->Retry()) break;
- }
- if (bytecount >= 0) {
- CopyThreadClass::_ActiveCopyThread->Add_Bytes_Copied ((unsigned)bytecount);
- }
- return (bytecount);
- } else {
-
- // NOTE: Returning -1 will cause the calling cabinet process to close all
- // files, release its resources, and return an error code to the caller of
- // FDICopy().
- return (-1);
- }
- }
- /***************************************************************************
- * int FAR DIAMONDAPI file_close( int hf )
- *=========================================================================*/
- FNCLOSE( file_close )
- {
- int result;
-
- while (!(result = CloseHandle ((void*) hf))) {
- if (!CopyThreadClass::_ActiveCopyThread->Retry()) break;
- }
- return (result ? 0 : -1);
- }
- /***************************************************************************
- * long FAR DIAMONDAPI file_seek( int hf, long dist, int seektype )
- *=========================================================================*/
- FNSEEK( file_seek )
- {
- long result;
- DWORD movemethod;
- // Map seek type to Win32.
- switch (seektype) {
- case SEEK_SET:
- movemethod = FILE_BEGIN;
- break;
- case SEEK_CUR:
- movemethod = FILE_CURRENT;
- break;
- case SEEK_END:
- movemethod = FILE_END;
- break;
- }
- while ((result = SetFilePointer ((void*) hf, dist, NULL, movemethod)) == 0xffffffff) {
- if (!CopyThreadClass::_ActiveCopyThread->Retry()) break;
- }
- return (result);
- }
- /******************************************************************************
- * int FAR DIAMONDAPI notification_function( FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin )
- *=============================================================================*/
- FNFDINOTIFY( notification_function )
- {
- static WideStringClass _targetpathname;
- static StringClass _multibytetemporarypathname;
- static FILETIME _sourcefiletime;
-
- switch (fdint) {
- case fdintCOPY_FILE:
- {
- FILETIME localfiletime;
-
- // Build target pathname.
- // NOTE: If the relative path does not contain subdirectories it will not contain a backslash.
- CopyThreadClass::_ActiveCopyThread->Get_Target_Path (_targetpathname);
- if (pfdin->psz1 [0] != '\\') _targetpathname += L"\\";
- _targetpathname += WideStringClass (pfdin->psz1);
- _Installer.Log (_targetpathname, pfdin->cb);
-
- // If target should be overwritten...
- if (!DosDateTimeToFileTime (pfdin->date, pfdin->time, &localfiletime)) return (-1);
- if (!LocalFileTimeToFileTime (&localfiletime, &_sourcefiletime)) return (-1);
-
- if (CopyThreadClass::Replace_File (_sourcefiletime, pfdin->cb, _targetpathname)) {
- WideStringClass statusmessage;
- long handle;
- WideStringClass targetpath;
- WideStringClass filename;
- // Update the name of the current file being copied.
- filename = WideStringClass (pfdin->psz1);
- Extract_Trailing_Name (filename);
- statusmessage.Format (COPY_MESSAGE_FORMAT_STRING, TxWideStringClass (IDS_COPYING), filename);
- CopyThreadClass::_ActiveCopyThread->Set_Status_Message (statusmessage);
- // Create temporary filename.
- targetpath = _targetpathname;
- Remove_Trailing_Name (targetpath);
- if (!Generate_Temporary_Pathname (targetpath, _multibytetemporarypathname)) return (-1);
- // Open the temporary file for writing.
- handle = file_open (_multibytetemporarypathname.Peek_Buffer(), _O_BINARY | _O_TRUNC | _O_CREAT | _O_WRONLY | _O_SEQUENTIAL, _S_IREAD | _S_IWRITE);
- // Add temporary filename to log.
- CopyThreadClass::_ActiveCopyThread->Get_Filename_Log().Add (_multibytetemporarypathname);
-
- return (handle);
- } else {
-
- // Do not copy file.
- CopyThreadClass::_ActiveCopyThread->Add_Bytes_Copied ((unsigned) pfdin->cb);
- return (0);
- }
- }
- case fdintCLOSE_FILE_INFO:
- {
- StringClass multibytetargetpathname;
- HANDLE targetfile;
- WIN32_FIND_DATA targetfiledata;
- int count;
- // Close the temporary file.
- if (file_close (pfdin->hf) != 0) return (-1);
- // Delete the original target file (if it exists).
- multibytetargetpathname = _targetpathname;
- targetfile = FindFirstFile (multibytetargetpathname, &targetfiledata);
- if (targetfile != INVALID_HANDLE_VALUE) {
- if (!FindClose (targetfile)) return (-1);
- if (targetfiledata.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
- if (!SetFileAttributes (multibytetargetpathname, FILE_ATTRIBUTE_NORMAL)) return (-1);
- }
- if (!DeleteFile (multibytetargetpathname)) return (-1);
- }
- // Rename the temporary file the target file.
- if (!MoveFile (_multibytetemporarypathname, multibytetargetpathname)) return (-1);
- // Remove the temporary file from the file log (the last item added).
- count = CopyThreadClass::_ActiveCopyThread->Get_Filename_Log().Count();
- WWASSERT (count > 0);
- CopyThreadClass::_ActiveCopyThread->Get_Filename_Log().Delete (count - 1);
- // Add the target file to the file log.
- CopyThreadClass::_ActiveCopyThread->Get_Filename_Log().Add (multibytetargetpathname);
- // Stamp the target file with write time of source.
- targetfile = CreateFile (multibytetargetpathname, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- if (targetfile == INVALID_HANDLE_VALUE) return (-1);
- if (!SetFileTime (targetfile, NULL, NULL, &_sourcefiletime)) return (-1);
- if (!CloseHandle (targetfile)) return (-1);
- // Stamp the target file with attributes of source.
- if (!SetFileAttributes (multibytetargetpathname, pfdin->attribs & (~FILE_ATTRIBUTE_READONLY))) return (-1);
- // Success.
- return (1);
- }
-
- case fdintNEXT_CABINET:
- {
- // Nothing to do. Assume that the next cabinet file is in the same directory as the current
- // cabinet file.
- return (1);
- }
- default:
- return (1);
- }
- }
- /***********************************************************************************************
- * CopyThreadClass::CopyThreadClass -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 08/22/01 IML : Created. *
- *=============================================================================================*/
- CopyThreadClass::CopyThreadClass (__int64 bytestocopy)
- : ThreadClass(),
- Status (STATUS_OK),
- Abort (false),
- CanAbort (true),
- AbortLock (NULL),
- IsAborting (false),
- BytesToCopy (bytestocopy),
- BytesCopied (0)
- {
- // Only one instance can be active.
- WWASSERT (_ActiveCopyThread == NULL);
- _ActiveCopyThread = this;
- }
- /***********************************************************************************************
- * CopyThreadClass::~CopyThreadClass -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 08/22/01 IML : Created. *
- *=============================================================================================*/
- CopyThreadClass::~CopyThreadClass()
- {
- WWASSERT (_ActiveCopyThread != NULL);
- _ActiveCopyThread = NULL;
- }
- /***********************************************************************************************
- * CopyThreadClass::Thread_Function -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 08/22/01 IML : Created. *
- *=============================================================================================*/
- void CopyThreadClass::Thread_Function()
- {
- try {
- unsigned i;
- WideStringClass sourcepath, targetpath;
- int gamesubdirectorycount, gamefilecount;
- // Copy the game directory if user requested it.
- if (_Installer.Install_Game()) {
-
- // Create game subdirectories on target.
- // NOTE 0: This could have been done whilst copying, but is more efficient to do here,
- // considering that InstallerClass already has this information.
- // NOTE 1: Directory paths should have been validated, so any errors here are fatal.
- if (!Create_Directory (_Installer.Get_Target_Game_Path (targetpath), &Get_Subdirectory_Log())) FATAL_SYSTEM_ERROR;
- i = 0;
- while (_Installer.Get_Target_Sub_Path (i, targetpath)) {
- _Installer.Log (targetpath);
- if (!Create_Directory (targetpath, &Get_Subdirectory_Log())) FATAL_SYSTEM_ERROR;
- i++;
- }
- Copy_Directory (_Installer.Get_Source_Game_Path (sourcepath), _Installer.Get_Target_Game_Path (targetpath));
- }
- gamesubdirectorycount = Get_Subdirectory_Log().Count();
- gamefilecount = Get_Filename_Log().Count();
- if (Is_Aborting()) goto abort;
- // Copy the WOL directory if user requested it.
- if (_Installer.Install_WOL()) {
- Copy_Directory (_Installer.Get_Source_WOL_Path (sourcepath), _Installer.Get_Target_WOL_Path (targetpath));
- }
- // Find out if the user wants to abort. At the same time disable the user's ability to abort
- // because the operations to follow are irreversible ie. this is the last chance for the
- // user to abort.
- if (Get_Abort (false)) goto abort;
- // Update registry and make start menu items.
- Set_Status_Message (TxWideStringClass (IDS_UPDATING_REGISTRY));
- _Installer.Update_Registry();
- // Make menu items and icons.
- Set_Status_Message (TxWideStringClass (IDS_MAKING_MENU_ITEMS));
- _Installer.Create_Links();
- // Create uninstall logs.
- Set_Status_Message (TxWideStringClass (IDS_CREATING_UNINSTALL_LOGS));
- _Installer.Create_Uninstall_Logs();
- // Indicate completion.
- Set_Status_Message (TxWideStringClass (IDS_INSTALLATION_COMPLETE));
- Status = STATUS_SUCCESS;
- return;
- abort:
- Set_Status_Message (WideStringClass (L""));
- Status = STATUS_ABORTED;
- // Remove installed components if game or WOL was freshly installed.
- if (_Installer.Is_Fresh_Game_Install() || _Installer.Is_Fresh_WOL_Install()) {
- int i;
- Set_Status_Message (TxWideStringClass (IDS_REMOVING_INSTALLED_COMPONENTS));
- // NOTE: Order of removal must be inverse of order of creation to ensure that leaf
- // subdirectories are removed before parent directories. To satisfy this
- // requirement, remove in the following order:
- // 1. WOL files (in any order).
- // 2. Game files (in any order).
- // 3. WOL subdirectories (in reverse order).
- // 4. Game subdirectories (in reverse order).
- if (_Installer.Is_Fresh_WOL_Install()) {
- for (i = gamefilecount; i < Get_Filename_Log().Count(); i++) {
- DeleteFile (Get_Filename_Log() [i]);
- }
- }
- if (_Installer.Is_Fresh_Game_Install()) {
- for (i = 0; i < gamefilecount; i++) {
- DeleteFile (Get_Filename_Log() [i]);
- }
- }
- if (_Installer.Is_Fresh_WOL_Install()) {
- for (i = Get_Subdirectory_Log().Count() - 1; i >= gamesubdirectorycount; i--) {
- RemoveDirectory (Get_Subdirectory_Log() [i]);
- }
- }
- if (_Installer.Is_Fresh_Game_Install()) {
- for (i = gamesubdirectorycount - 1; i >= 0; i--) {
- RemoveDirectory (Get_Subdirectory_Log() [i]);
- }
- }
- // Give time for user to read status message.
- Sleep (5000);
- }
-
- } catch (const WideStringClass &errormessage) {
- // Copy off the errormessage so that it can be interrogated by the thread creator.
- Set_Status_Message (WideStringClass (L""));
- Set_Error_Message (errormessage);
- Status = STATUS_FAILURE;
- }
- }
- /***********************************************************************************************
- * CopyThreadClass::Copy_Directory -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 08/22/01 IML : Created. *
- *=============================================================================================*/
- void CopyThreadClass::Copy_Directory (const WideStringClass &sourcepath, const WideStringClass &targetpath)
- {
- // WARNING: Do not call SetCurrentDirectory() from this thread because it will affect
- // file access for the entire process.
- const WCHAR *wildcardname = L"*.*";
- HFDI hfdi;
- ERF erf;
- WideStringClass sourcepathname;
- StringClass multibytesourcepathname;
- WIN32_FIND_DATA finddata;
- HANDLE handle;
- bool done = false;
- hfdi = FDICreate (fdi_mem_alloc, // Memory allocation function.
- fdi_mem_free, // Memory free function.
- file_open, // File open function.
- file_read, // File read function.
- file_write, // File write function.
- file_close, // File close function.
- file_seek, // File seek function.
- cpu80386, // Type of CPU.
- &erf); // Pointer to error structure.
- WWASSERT (hfdi != NULL);
- // Create subdirectory (if it doesn't already exist).
- if (!Create_Directory (targetpath, &Get_Subdirectory_Log())) FATAL_SYSTEM_ERROR;
- // Iterate over files in source directory and copy to target directory.
- sourcepathname = sourcepath;
- sourcepathname += L"\\";
- sourcepathname += wildcardname;
- multibytesourcepathname = sourcepathname;
-
- // Find a source file.
- // NOTE At least one file must be in the directory.
- while ((handle = FindFirstFile (multibytesourcepathname, &finddata)) == INVALID_HANDLE_VALUE) {
- if (!Retry()) FATAL_SYSTEM_ERROR;
- }
- while (!done && !Is_Aborting()) {
- WideStringClass filename (finddata.cFileName);
- // Filter out system files.
- if (filename [0] != L'.') {
- // Is it a subdirectory?
- if (finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- WideStringClass subsourcepath (sourcepath);
- WideStringClass subtargetpath (targetpath);
- // Recurse.
- subsourcepath += L"\\";
- subsourcepath += filename;
- subtargetpath += L"\\";
- subtargetpath += filename;
- _Installer.Log (subtargetpath);
-
- Copy_Directory (subsourcepath, subtargetpath);
- } else {
-
- const WCHAR *cabextension = L".cab";
- WCHAR extension [_MAX_EXT];
- // Is it a CAB file?
- _wsplitpath (filename, NULL, NULL, NULL, extension);
- if (_wcsicmp (cabextension, extension) == 0) {
- StringClass sourcepathbackslash (sourcepath);
- // NOTE: FDICopy() requires a trailing backslash on the source path.
- sourcepathbackslash += "\\";
- Set_Target_Path (targetpath);
-
- // Copy the contents of the cabinet file to the target directory.
- // If the function fails then throw a 'cabinet error'.
- if (!FDICopy (hfdi, // Handle to FDI context (created by FDICreate()).
- finddata.cFileName, // Name of cabinet file, excluding path information.
- sourcepathbackslash.Peek_Buffer(), // File path to cabinet file.
- 0, // Flags to control extract operation.
- notification_function, // Ptr to a notification (status update) function.
- NULL, // Ptr to a decryption function.
- NULL))
-
- // If failure was not due to user aborting then throw an error.
- if (!Is_Aborting()) FATAL_CAB_ERROR (erf.erfOper);
- } else {
-
- // Update the name of the current file being copied.
- WideStringClass statusmessage;
- __int64 filesize;
- statusmessage.Format (COPY_MESSAGE_FORMAT_STRING, TxWideStringClass (IDS_COPYING), filename);
- Set_Status_Message (statusmessage);
- // It's a regular file.
- WideStringClass sourcepathname (sourcepath);
- WideStringClass targetpathname (targetpath);
- sourcepathname += L"\\";
- sourcepathname += filename;
- targetpathname += L"\\";
- targetpathname += filename;
-
- filesize = ((((__int64)MAXDWORD) + 1) * ((__int64) finddata.nFileSizeHigh)) + ((__int64) finddata.nFileSizeLow);
- _Installer.Log (targetpathname, filesize);
-
- // If target should be overwitten...
- if (Replace_File (sourcepathname, targetpathname)) {
- Copy_File (sourcepathname, targetpathname);
- } else {
- BytesCopied += filesize;
- }
- }
- }
- }
-
- if (Is_Aborting()) break;
-
- while (done = (FindNextFile (handle, &finddata) == 0)) {
- if (GetLastError() == ERROR_NO_MORE_FILES) break;
- if (!Retry()) FATAL_SYSTEM_ERROR;
- }
- }
-
- while (!FindClose (handle)) {
- if (!Retry()) FATAL_SYSTEM_ERROR;
- }
- FDIDestroy (hfdi);
- }
- /***********************************************************************************************
- * CopyThreadClass::Copy_File -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 08/22/01 IML : Created. *
- *=============================================================================================*/
- void CopyThreadClass::Copy_File (const WideStringClass &sourcepathname, const WideStringClass &targetpathname)
- {
- const unsigned buffersize = 32768;
- static char _buffer [buffersize];
-
- StringClass multibytesourcepathname, multibytetargetpathname;
- WideStringClass targetpath;
- StringClass multibytetargetpath, multibytetemporarypathname;
- HANDLE sourcefile, temporaryfile, targetfile;
- DWORD sourcebytecount, bytecount;
- WIN32_FIND_DATA sourcefiledata, targetfiledata;
- multibytesourcepathname = sourcepathname;
- multibytetargetpathname = targetpathname;
- // Open the read file.
- while ((sourcefile = CreateFile (multibytesourcepathname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) {
- if (!Retry()) FATAL_SYSTEM_ERROR;
- }
- // Create temporary file.
- targetpath = targetpathname;
- Remove_Trailing_Name (targetpath);
- if (!Generate_Temporary_Pathname (targetpath, multibytetemporarypathname)) FATAL_SYSTEM_ERROR;
-
- // Open the temporary file for writing.
- temporaryfile = CreateFile (multibytetemporarypathname, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, NULL);
- if (temporaryfile == INVALID_HANDLE_VALUE) FATAL_SYSTEM_ERROR;
-
- do {
-
- // Abort the copying process?
- if (Get_Abort (true)) break;
- while (!ReadFile (sourcefile, _buffer, buffersize, &sourcebytecount, NULL)) {
- if (!Retry()) FATAL_SYSTEM_ERROR;
- }
- if (!WriteFile (temporaryfile, _buffer, sourcebytecount, &bytecount, NULL)) FATAL_SYSTEM_ERROR;
- BytesCopied += sourcebytecount;
- } while (sourcebytecount == buffersize);
- // Close.
- while (!CloseHandle (sourcefile)) {
- if (!Retry()) FATAL_SYSTEM_ERROR;
- }
- while (!CloseHandle (temporaryfile)) {
- if (!Retry()) FATAL_SYSTEM_ERROR;
- }
- while ((sourcefile = FindFirstFile (multibytesourcepathname, &sourcefiledata)) == INVALID_HANDLE_VALUE) {
- if (!Retry()) FATAL_SYSTEM_ERROR;
- }
- while (!FindClose (sourcefile)) {
- if (!Retry()) FATAL_SYSTEM_ERROR;
- }
- // Delete the original target file (if it exists).
- targetfile = FindFirstFile (multibytetargetpathname, &targetfiledata);
- if (targetfile != INVALID_HANDLE_VALUE) {
- if (!FindClose (targetfile)) FATAL_SYSTEM_ERROR;
- if (targetfiledata.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
- if (!SetFileAttributes (multibytetargetpathname, FILE_ATTRIBUTE_NORMAL)) FATAL_SYSTEM_ERROR;
- }
- if (!DeleteFile (multibytetargetpathname)) FATAL_SYSTEM_ERROR;
- }
- // Rename the temporary file the original target file.
- if (!MoveFile (multibytetemporarypathname, multibytetargetpathname)) FATAL_SYSTEM_ERROR;
- // Add the name of the file to the file log.
- Get_Filename_Log().Add (multibytetargetpathname);
- // Stamp the target file with write time of source.
- targetfile = CreateFile (multibytetargetpathname, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- if (targetfile == INVALID_HANDLE_VALUE) FATAL_SYSTEM_ERROR;
- if (!SetFileTime (targetfile, NULL, NULL, &sourcefiledata.ftLastWriteTime)) FATAL_SYSTEM_ERROR;
- if (!CloseHandle (targetfile)) FATAL_SYSTEM_ERROR;
- // Stamp the target file with file attributes of source (but clear the read-only flag to ensure that
- // the file can be patched at a later date).
- if (!SetFileAttributes (multibytetargetpathname, sourcefiledata.dwFileAttributes & (~FILE_ATTRIBUTE_READONLY))) FATAL_SYSTEM_ERROR;
- }
- /***********************************************************************************************
- * Replace_File -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 08/22/01 IML : Created. *
- *=============================================================================================*/
- bool CopyThreadClass::Replace_File (const FILETIME &sourcefiletime, DWORD sourcefilesize, const WideStringClass &targetpathname)
- {
- StringClass multibytetargetpathname (targetpathname);
- WIN32_FIND_DATA targetdata;
- HANDLE handle;
- long t;
- // Does the target file exist?
- handle = FindFirstFile (multibytetargetpathname, &targetdata);
- if (handle == INVALID_HANDLE_VALUE) return (true);
- // Test last write times.
- t = CompareFileTime (&sourcefiletime, &targetdata.ftLastWriteTime);
- if (t > 0) return (true);
- if (t < 0) return (false);
- // So far files are deemed equal. To err on the side of caution, test file sizes and elect to replace the file if sizes differ.
- return ((sourcefilesize != targetdata.nFileSizeLow) || (targetdata.nFileSizeHigh != 0));
- }
- /***********************************************************************************************
- * Replace_File -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 08/22/01 IML : Created. *
- *=============================================================================================*/
- bool CopyThreadClass::Replace_File (const WideStringClass &sourcepathname, const WideStringClass &targetpathname)
- {
- StringClass multibytesourcepathname (sourcepathname);
- StringClass multibytetargetpathname (targetpathname);
- WIN32_FIND_DATA sourcedata, targetdata;
- HANDLE handle;
- VS_FIXEDFILEINFO sourceversion, targetversion;
- long t;
- // Find source file. It must exist.
- while ((handle = FindFirstFile (multibytesourcepathname, &sourcedata)) == INVALID_HANDLE_VALUE) {
- if (!_ActiveCopyThread->Retry()) FATAL_SYSTEM_ERROR;
- }
- // Does the target file exist?
- handle = FindFirstFile (multibytetargetpathname, &targetdata);
- if (handle == INVALID_HANDLE_VALUE) return (true);
- // Test version numbers (if they exist).
- if (GetVersionInfo (multibytesourcepathname.Peek_Buffer(), &sourceversion) && GetVersionInfo (multibytetargetpathname.Peek_Buffer(), &targetversion)) {
- if (sourceversion.dwFileVersionMS > targetversion.dwFileVersionMS) return (true);
- if (sourceversion.dwFileVersionMS < targetversion.dwFileVersionMS) return (false);
- if (sourceversion.dwFileVersionLS > targetversion.dwFileVersionLS) return (true);
- if (sourceversion.dwFileVersionLS < targetversion.dwFileVersionLS) return (false);
- }
- // Test last write times.
- t = CompareFileTime (&sourcedata.ftLastWriteTime, &targetdata.ftLastWriteTime);
- if (t > 0) return (true);
- if (t < 0) return (false);
- // So far files are deemed equal. To err on the side of caution, test file sizes and elect to replace the file if sizes differ.
- return ((sourcedata.nFileSizeLow != targetdata.nFileSizeLow) || (sourcedata.nFileSizeHigh != targetdata.nFileSizeHigh));
- }
- /***********************************************************************************************
- * CopyThreadClass::Can_Abort -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 08/22/01 IML : Created. *
- *=============================================================================================*/
- bool CopyThreadClass::Can_Abort (bool lock)
- {
- if (lock) {
- if (AbortLock == NULL) {
- AbortLock = new FastCriticalSectionClass::LockClass (SectionAbort);
- }
- return (CanAbort);
- } else {
- FastCriticalSectionClass::LockClass cs (SectionAbort);
- return (CanAbort);
- }
- }
- /***********************************************************************************************
- * CopyThreadClass::Set_Abort -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 08/22/01 IML : Created. *
- *=============================================================================================*/
- void CopyThreadClass::Set_Abort (bool abort)
- {
- Abort = abort;
- WWASSERT (AbortLock != NULL);
- delete AbortLock;
- AbortLock = NULL;
- }
- /***********************************************************************************************
- * CopyThreadClass::Get_Abort -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 08/22/01 IML : Created. *
- *=============================================================================================*/
- bool CopyThreadClass::Get_Abort (bool canabort)
- {
- FastCriticalSectionClass::LockClass cs (SectionAbort);
-
- CanAbort = canabort;
- if (Abort) IsAborting = true;
- return (Abort);
- }
- /***********************************************************************************************
- * CopyThreadClass::Add_Bytes_Copied -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 08/22/01 IML : Created. *
- *=============================================================================================*/
- void CopyThreadClass::Add_Bytes_Copied (unsigned bytecount)
- {
- FastCriticalSectionClass::LockClass cs (SectionBytesCopied);
- BytesCopied += bytecount;
- }
- /***********************************************************************************************
- * CopyThreadClass::Get_Fraction_Complete -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 08/22/01 IML : Created. *
- *=============================================================================================*/
- float CopyThreadClass::Get_Fraction_Complete()
- {
- FastCriticalSectionClass::LockClass cs (SectionBytesCopied);
- float fraction;
- fraction = ((double) BytesCopied) / ((double) BytesToCopy);
-
- // Clamp to valid range.
- fraction = MAX (0.0f, MIN (1.0f, fraction));
- return (fraction);
- }
- /***********************************************************************************************
- * CopyThreadClass::Set\Get_Target_Path -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 08/22/01 IML : Created. *
- *=============================================================================================*/
- void CopyThreadClass::Set_Target_Path (const WideStringClass &targetpath)
- {
- FastCriticalSectionClass::LockClass cs (SectionTargetPath);
-
- TargetPath = targetpath;
- }
- WCHAR *CopyThreadClass::Get_Target_Path (WideStringClass &targetpath)
- {
- FastCriticalSectionClass::LockClass cs (SectionTargetPath);
-
- targetpath = TargetPath;
- return (targetpath.Peek_Buffer());
- }
- /***********************************************************************************************
- * CopyThreadClass::Set\Get_Status_Message -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 08/22/01 IML : Created. *
- *=============================================================================================*/
- void CopyThreadClass::Set_Status_Message (const WideStringClass &statusmessage)
- {
- FastCriticalSectionClass::LockClass cs (SectionStatusMessage);
-
- StatusMessage = statusmessage;
- }
- WCHAR *CopyThreadClass::Get_Status_Message (WideStringClass &statusmessage)
- {
- FastCriticalSectionClass::LockClass cs (SectionStatusMessage);
-
- statusmessage = StatusMessage;
- return (statusmessage.Peek_Buffer());
- }
- /***********************************************************************************************
- * CopyThreadClass::Set\Get_Error_Message -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 08/22/01 IML : Created. *
- *=============================================================================================*/
- void CopyThreadClass::Set_Error_Message (const WideStringClass &errormessage)
- {
- FastCriticalSectionClass::LockClass cs (SectionErrorMessage);
-
- ErrorMessage = errormessage;
- }
- WCHAR *CopyThreadClass::Get_Error_Message (WideStringClass &errormessage)
- {
- FastCriticalSectionClass::LockClass cs (SectionErrorMessage);
-
- errormessage = ErrorMessage;
- return (errormessage.Peek_Buffer());
- }
- /***********************************************************************************************
- * CopyThreadClass::Set\Get_Status -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 08/22/01 IML : Created. *
- *=============================================================================================*/
- void CopyThreadClass::Set_Status (StatusEnum status)
- {
- FastCriticalSectionClass::LockClass cs (SectionStatus);
-
- Status = status;
- }
- CopyThreadClass::StatusEnum CopyThreadClass::Get_Status()
- {
- FastCriticalSectionClass::LockClass cs (SectionStatus);
-
- return (Status);
- }
- /***********************************************************************************************
- * CopyThreadClass::Retry -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 08/22/01 IML : Created. *
- *=============================================================================================*/
- bool CopyThreadClass::Retry()
- {
- CopyThreadClass::StatusEnum status;
- Set_Status (STATUS_ERROR);
- while ((status = Get_Status()) == STATUS_ERROR) {
- Sleep (50);
- }
- return (status == STATUS_RETRY);
- }
|