/* * 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); }