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.
347 lines
9.7 KiB
347 lines
9.7 KiB
/*
|
|
* file.c - File routines module.
|
|
*/
|
|
|
|
|
|
/* Headers
|
|
**********/
|
|
|
|
#include "project.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
/* Constants
|
|
************/
|
|
|
|
/* size of file comparison buffer in bytes */
|
|
|
|
#define COMP_BUF_SIZE (16U * 1024U)
|
|
|
|
|
|
/* Module Variables
|
|
*******************/
|
|
|
|
/* lock count for file comparison buffer */
|
|
|
|
PRIVATE_DATA ULONG MulcCompBufLock = 0;
|
|
|
|
/* buffers for file comparison */
|
|
|
|
PRIVATE_DATA PBYTE MrgbyteCompBuf1 = NULL;
|
|
PRIVATE_DATA PBYTE MrgbyteCompBuf2 = NULL;
|
|
|
|
/* length of file comparison buffers in bytes */
|
|
|
|
PRIVATE_DATA UINT MucbCompBufLen = 0;
|
|
|
|
|
|
/****************************** Public Functions *****************************/
|
|
|
|
|
|
/*
|
|
** BeginComp()
|
|
**
|
|
** Increments file comparison buffers' lock count.
|
|
**
|
|
** Arguments: void
|
|
**
|
|
** Returns: TWINRESULT
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PUBLIC_CODE void BeginComp(void)
|
|
{
|
|
ASSERT((MrgbyteCompBuf1 && MrgbyteCompBuf2 && MucbCompBufLen > 0) ||
|
|
(! MrgbyteCompBuf1 && ! MrgbyteCompBuf2 && ! MucbCompBufLen));
|
|
|
|
ASSERT(MulcCompBufLock < ULONG_MAX);
|
|
MulcCompBufLock++;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
** EndComp()
|
|
**
|
|
** Decrements file comparison buffers' lock count.
|
|
**
|
|
** Arguments: void
|
|
**
|
|
** Returns: void
|
|
**
|
|
** Side Effects: Frees file comparison buffers if lock count goes to 0.
|
|
*/
|
|
PUBLIC_CODE void EndComp(void)
|
|
{
|
|
ASSERT((MrgbyteCompBuf1 && MrgbyteCompBuf2 && MucbCompBufLen > 0) ||
|
|
(! MrgbyteCompBuf1 && ! MrgbyteCompBuf2 && ! MucbCompBufLen));
|
|
ASSERT(MulcCompBufLock > 0 || (! MrgbyteCompBuf1 && ! MrgbyteCompBuf2 && ! MucbCompBufLen));
|
|
|
|
if (EVAL(MulcCompBufLock > 0))
|
|
MulcCompBufLock--;
|
|
|
|
/* Are the comparison buffers still locked? */
|
|
|
|
if (! MulcCompBufLock && MrgbyteCompBuf1 && MrgbyteCompBuf2)
|
|
{
|
|
/* No. Free them. */
|
|
|
|
FreeMemory(MrgbyteCompBuf1);
|
|
MrgbyteCompBuf1 = NULL;
|
|
|
|
FreeMemory(MrgbyteCompBuf2);
|
|
MrgbyteCompBuf2 = NULL;
|
|
|
|
TRACE_OUT((TEXT("EndComp(): Two %u byte file comparison buffers freed."),
|
|
MucbCompBufLen));
|
|
|
|
MucbCompBufLen = 0;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
** CompareFilesByHandle()
|
|
**
|
|
** Determines whether or not two files are the same.
|
|
**
|
|
** Arguments: h1 - DOS file handle to first open file
|
|
** h2 - DOS file handle to second open file
|
|
** pbIdentical - pointer to BOOL to be filled in with value
|
|
** indicating whether or not the files are
|
|
** identical
|
|
**
|
|
** Returns: TWINRESULT
|
|
**
|
|
** Side Effects: Changes the position of the file pointer of each file.
|
|
*/
|
|
PUBLIC_CODE TWINRESULT CompareFilesByHandle(HANDLE h1, HANDLE h2,
|
|
PBOOL pbIdentical)
|
|
{
|
|
TWINRESULT tr;
|
|
|
|
ASSERT(IS_VALID_HANDLE(h1, FILE));
|
|
ASSERT(IS_VALID_HANDLE(h2, FILE));
|
|
ASSERT(IS_VALID_WRITE_PTR(pbIdentical, BOOL));
|
|
|
|
ASSERT((MrgbyteCompBuf1 && MrgbyteCompBuf2 && MucbCompBufLen > 0) ||
|
|
(! MrgbyteCompBuf1 && ! MrgbyteCompBuf2 && ! MucbCompBufLen));
|
|
ASSERT(MulcCompBufLock || (! MrgbyteCompBuf1 && ! MrgbyteCompBuf2 && ! MucbCompBufLen));
|
|
|
|
/* Have the comparison buffers already been allocated? */
|
|
|
|
if (MrgbyteCompBuf1)
|
|
tr = TR_SUCCESS;
|
|
else
|
|
{
|
|
/* No. Allocate them. */
|
|
|
|
tr = TR_OUT_OF_MEMORY;
|
|
|
|
if (AllocateMemory(COMP_BUF_SIZE, &MrgbyteCompBuf1))
|
|
{
|
|
if (AllocateMemory(COMP_BUF_SIZE, &MrgbyteCompBuf2))
|
|
{
|
|
/* Success! */
|
|
|
|
MucbCompBufLen = COMP_BUF_SIZE;
|
|
tr = TR_SUCCESS;
|
|
|
|
TRACE_OUT((TEXT("CompareFilesByHandle(): Two %u byte file comparison buffers allocated."),
|
|
MucbCompBufLen));
|
|
}
|
|
else
|
|
{
|
|
FreeMemory(MrgbyteCompBuf1);
|
|
MrgbyteCompBuf1 = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (tr == TR_SUCCESS)
|
|
{
|
|
DWORD dwcbLen1;
|
|
|
|
BeginComp();
|
|
|
|
/* Get file lengths to compare. */
|
|
|
|
tr = TR_SRC_READ_FAILED;
|
|
|
|
dwcbLen1 = SetFilePointer(h1, 0, NULL, FILE_END);
|
|
|
|
if (dwcbLen1 != INVALID_SEEK_POSITION)
|
|
{
|
|
DWORD dwcbLen2;
|
|
|
|
dwcbLen2 = SetFilePointer(h2, 0, NULL, FILE_END);
|
|
|
|
if (dwcbLen2 != INVALID_SEEK_POSITION)
|
|
{
|
|
/* Are the files the same length? */
|
|
|
|
if (dwcbLen1 == dwcbLen2)
|
|
{
|
|
/* Yes. Move to the beginning of the files. */
|
|
|
|
if (SetFilePointer(h1, 0, NULL, FILE_BEGIN) != INVALID_SEEK_POSITION)
|
|
{
|
|
if (SetFilePointer(h2, 0, NULL, FILE_BEGIN) != INVALID_SEEK_POSITION)
|
|
{
|
|
tr = TR_SUCCESS;
|
|
|
|
do
|
|
{
|
|
DWORD dwcbRead1;
|
|
|
|
if (ReadFile(h1, MrgbyteCompBuf1, MucbCompBufLen, &dwcbRead1, NULL))
|
|
{
|
|
DWORD dwcbRead2;
|
|
|
|
if (ReadFile(h2, MrgbyteCompBuf2, MucbCompBufLen, &dwcbRead2, NULL))
|
|
{
|
|
if (dwcbRead1 == dwcbRead2)
|
|
{
|
|
/* At EOF? */
|
|
|
|
if (! dwcbRead1)
|
|
{
|
|
/* Yes. */
|
|
|
|
*pbIdentical = TRUE;
|
|
break;
|
|
}
|
|
else if (MyMemComp(MrgbyteCompBuf1, MrgbyteCompBuf2, dwcbRead1) != CR_EQUAL)
|
|
{
|
|
/* Yes. */
|
|
|
|
*pbIdentical = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
tr = TR_SRC_READ_FAILED;
|
|
}
|
|
else
|
|
tr = TR_SRC_READ_FAILED;
|
|
}
|
|
else
|
|
tr = TR_SRC_READ_FAILED;
|
|
} while (tr == TR_SUCCESS);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* No. Files different lengths. */
|
|
|
|
*pbIdentical = FALSE;
|
|
|
|
tr = TR_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
|
|
EndComp();
|
|
}
|
|
|
|
return(tr);
|
|
}
|
|
|
|
|
|
/*
|
|
** CompareFilesByName()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns: TWINRESULT
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PUBLIC_CODE TWINRESULT CompareFilesByName(HPATH hpath1, HPATH hpath2,
|
|
PBOOL pbIdentical)
|
|
{
|
|
TWINRESULT tr;
|
|
|
|
ASSERT(IS_VALID_HANDLE(hpath1, PATH));
|
|
ASSERT(IS_VALID_HANDLE(hpath2, PATH));
|
|
ASSERT(IS_VALID_WRITE_PTR(pbIdentical, BOOL));
|
|
|
|
/* Only verify source and destination volumes once up front. */
|
|
|
|
if (IsPathVolumeAvailable(hpath1) &&
|
|
IsPathVolumeAvailable(hpath2))
|
|
{
|
|
HANDLE h1;
|
|
TCHAR rgchFile1[MAX_PATH_LEN];
|
|
|
|
/* Try to open files. Assume sequential reads. */
|
|
|
|
GetPathString(hpath1, 0, rgchFile1, ARRAYSIZE(rgchFile1));
|
|
|
|
h1 = CreateFile(rgchFile1, GENERIC_READ, FILE_SHARE_READ, NULL,
|
|
OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
|
|
|
if (h1 != INVALID_HANDLE_VALUE)
|
|
{
|
|
HANDLE h2;
|
|
TCHAR rgchFile2[MAX_PATH_LEN];
|
|
|
|
GetPathString(hpath2, 0, rgchFile2, ARRAYSIZE(rgchFile2));
|
|
|
|
h2 = CreateFile(rgchFile2, GENERIC_READ, FILE_SHARE_READ, NULL,
|
|
OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
|
|
|
if (h2 != INVALID_HANDLE_VALUE)
|
|
{
|
|
TRACE_OUT((TEXT("CompareFilesByHandle(): Comparing files %s and %s."),
|
|
DebugGetPathString(hpath1),
|
|
DebugGetPathString(hpath2)));
|
|
|
|
tr = CompareFilesByHandle(h1, h2, pbIdentical);
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (tr == TR_SUCCESS)
|
|
{
|
|
if (*pbIdentical)
|
|
TRACE_OUT((TEXT("CompareFilesByHandle(): %s and %s are identical."),
|
|
DebugGetPathString(hpath1),
|
|
DebugGetPathString(hpath2)));
|
|
else
|
|
TRACE_OUT((TEXT("CompareFilesByHandle(): %s and %s are different."),
|
|
DebugGetPathString(hpath1),
|
|
DebugGetPathString(hpath2)));
|
|
}
|
|
|
|
#endif
|
|
|
|
/*
|
|
* Failing to close the file properly is not a failure condition here.
|
|
*/
|
|
|
|
CloseHandle(h2);
|
|
}
|
|
else
|
|
tr = TR_DEST_OPEN_FAILED;
|
|
|
|
/*
|
|
* Failing to close the file properly is not a failure condition here.
|
|
*/
|
|
|
|
CloseHandle(h1);
|
|
}
|
|
else
|
|
tr = TR_SRC_OPEN_FAILED;
|
|
}
|
|
else
|
|
tr = TR_UNAVAILABLE_VOLUME;
|
|
|
|
return(tr);
|
|
}
|
|
|