diff --git a/DirHash.cpp b/DirHash.cpp index 2537aa5..f70136d 100644 --- a/DirHash.cpp +++ b/DirHash.cpp @@ -39,6 +39,7 @@ using namespace std; static BYTE g_pbBuffer[4096]; +static TCHAR g_szCanonalizedName[MAX_PATH + 1]; // Used for sorting directory content bool compare_nocase (LPCWSTR first, LPCWSTR second) @@ -52,7 +53,7 @@ class Hash { public: virtual void Init() = 0; - virtual void Update(LPBYTE pbData, DWORD dwLength) = 0; + virtual void Update(LPBYTE pbData, size_t dwLength) = 0; virtual void Final(LPBYTE pbDigest) = 0; virtual int GetHashSize() = 0; virtual LPCTSTR GetID() = 0; @@ -70,7 +71,7 @@ class Md5 : public Hash } void Init() { MD5_Init(&m_ctx);} - void Update(LPBYTE pbData, DWORD dwLength) { MD5_Update(&m_ctx, pbData, dwLength);} + void Update(LPBYTE pbData, size_t dwLength) { MD5_Update(&m_ctx, pbData, dwLength);} void Final(LPBYTE pbDigest) { MD5_Final(pbDigest, &m_ctx);} LPCTSTR GetID() { return _T("MD5");} int GetHashSize() { return 16;} @@ -87,7 +88,7 @@ class Sha1 : public Hash } void Init() { SHA1_Init(&m_ctx);} - void Update(LPBYTE pbData, DWORD dwLength) { SHA1_Update(&m_ctx, pbData, dwLength);} + void Update(LPBYTE pbData, size_t dwLength) { SHA1_Update(&m_ctx, pbData, dwLength);} void Final(LPBYTE pbDigest) { SHA1_Final(pbDigest, &m_ctx);} LPCTSTR GetID() { return _T("SHA1");} int GetHashSize() { return 20;} @@ -104,7 +105,7 @@ class Sha256 : public Hash } void Init() { SHA256_Init(&m_ctx);} - void Update(LPBYTE pbData, DWORD dwLength) { SHA256_Update(&m_ctx, pbData, dwLength);} + void Update(LPBYTE pbData, size_t dwLength) { SHA256_Update(&m_ctx, pbData, dwLength);} void Final(LPBYTE pbDigest) { SHA256_Final(pbDigest, &m_ctx);} LPCTSTR GetID() { return _T("SHA256");} int GetHashSize() { return 32;} @@ -121,7 +122,7 @@ class Sha384 : public Hash } void Init() { SHA384_Init(&m_ctx);} - void Update(LPBYTE pbData, DWORD dwLength) { SHA384_Update(&m_ctx, pbData, dwLength);} + void Update(LPBYTE pbData, size_t dwLength) { SHA384_Update(&m_ctx, pbData, dwLength);} void Final(LPBYTE pbDigest) { SHA384_Final(pbDigest, &m_ctx);} LPCTSTR GetID() { return _T("SHA384");} int GetHashSize() { return 48;} @@ -138,7 +139,7 @@ class Sha512 : public Hash } void Init() { SHA512_Init(&m_ctx);} - void Update(LPBYTE pbData, DWORD dwLength) { SHA512_Update(&m_ctx, pbData, dwLength);} + void Update(LPBYTE pbData, size_t dwLength) { SHA512_Update(&m_ctx, pbData, dwLength);} void Final(LPBYTE pbDigest) { SHA512_Final(pbDigest, &m_ctx);} LPCTSTR GetID() { return _T("SHA512");} int GetHashSize() { return 64;} @@ -194,17 +195,37 @@ class CDirContent operator LPCWSTR () { return m_szPath.c_str();} }; -DWORD HashFile(LPCTSTR szFilePath, Hash* pHash, bool bIncludeNames) +bool IsExcludedName(LPCTSTR szName, list& excludeSpecList) +{ + for (list::iterator It = excludeSpecList.begin(); It != excludeSpecList.end(); It++) + { + if (PathMatchSpec (szName, It->c_str())) + return true; + } + + return false; +} + +DWORD HashFile(LPCTSTR szFilePath, Hash* pHash, bool bIncludeNames, list& excludeSpecList) { DWORD dwError = 0; FILE* f = NULL; + int pathLen = lstrlen(szFilePath); + + if (pathLen <= MAX_PATH && !excludeSpecList.empty() && IsExcludedName (szFilePath, excludeSpecList)) + return 0; if (bIncludeNames) { - TCHAR szCanonalizedName[MAX_PATH + 1]; - if (!PathCanonicalize (szCanonalizedName, szFilePath)) - lstrcpy (szCanonalizedName, szFilePath); - pHash->Update ((LPBYTE) szCanonalizedName, _tcslen (szCanonalizedName) * sizeof(TCHAR)); + if (pathLen > MAX_PATH) + pHash->Update ((LPBYTE) szFilePath, _tcslen (szFilePath) * sizeof(TCHAR)); + else + { + g_szCanonalizedName[MAX_PATH] = 0; + if (!PathCanonicalize (g_szCanonalizedName, szFilePath)) + lstrcpy (g_szCanonalizedName, szFilePath); + pHash->Update ((LPBYTE) g_szCanonalizedName, _tcslen (g_szCanonalizedName) * sizeof(TCHAR)); + } } f = _tfopen(szFilePath, _T("rb")); @@ -224,20 +245,29 @@ DWORD HashFile(LPCTSTR szFilePath, Hash* pHash, bool bIncludeNames) return dwError; } -DWORD HashDirectory(LPCTSTR szDirPath, Hash* pHash, bool bIncludeNames) +DWORD HashDirectory(LPCTSTR szDirPath, Hash* pHash, bool bIncludeNames, list& excludeSpecList) { wstring szDir; WIN32_FIND_DATA ffd; HANDLE hFind = INVALID_HANDLE_VALUE; DWORD dwError=0; list dirContent; + int pathLen = lstrlen(szDirPath); + + if (pathLen <= MAX_PATH && !excludeSpecList.empty() && IsExcludedName (szDirPath, excludeSpecList)) + return 0; if (bIncludeNames) { - TCHAR szCanonalizedName[MAX_PATH + 1]; - if (!PathCanonicalize (szCanonalizedName, szDirPath)) - lstrcpy (szCanonalizedName, szDirPath); - pHash->Update ((LPBYTE) szCanonalizedName, _tcslen (szCanonalizedName) * sizeof(TCHAR)); + if (lstrlen(szDirPath) > MAX_PATH) + pHash->Update ((LPBYTE) szDirPath, _tcslen (szDirPath) * sizeof(TCHAR)); + else + { + g_szCanonalizedName[MAX_PATH] = 0; + if (!PathCanonicalize (g_szCanonalizedName, szDirPath)) + lstrcpy (g_szCanonalizedName, szDirPath); + pHash->Update ((LPBYTE) g_szCanonalizedName, _tcslen (g_szCanonalizedName) * sizeof(TCHAR)); + } } szDir += szDirPath; @@ -290,13 +320,13 @@ DWORD HashDirectory(LPCTSTR szDirPath, Hash* pHash, bool bIncludeNames) { if (it->IsDir()) { - dwError = HashDirectory( it->GetPath(), pHash, bIncludeNames); + dwError = HashDirectory( it->GetPath(), pHash, bIncludeNames, excludeSpecList); if (dwError) break; } else { - dwError = HashFile(it->GetPath(), pHash, bIncludeNames); + dwError = HashFile(it->GetPath(), pHash, bIncludeNames, excludeSpecList); if (dwError) break; } @@ -307,7 +337,7 @@ DWORD HashDirectory(LPCTSTR szDirPath, Hash* pHash, bool bIncludeNames) void ShowUsage() { - _tprintf(TEXT("Usage: DirHash.exe DirectoryOrFilePath [HashAlgo] [-t ResultFileName] [-nowait] [-hashnames]\n Possible values for HashAlgo (not case sensitive, default is SHA1) : \n - MD5\n - SHA1\n - SHA256\n - SHA384\n - SHA512\n\n ResultFileName specifies a text file where the result will be appended\n\n -nowait avoids displaying the waiting prompt before exiting\n\n -hashnames indicates that file names will be included in the hash computation")); + _tprintf(TEXT("Usage: DirHash.exe DirectoryOrFilePath [HashAlgo] [-t ResultFileName] [-nowait] [-hashnames] [-exclude pattern1] [-exclude pattern2]\n Possible values for HashAlgo (not case sensitive, default is SHA1) : \n - MD5\n - SHA1\n - SHA256\n - SHA384\n - SHA512\n\n ResultFileName specifies a text file where the result will be appended\n\n -nowait avoids displaying the waiting prompt before exiting\n\n -hashnames indicates that file names will be included in the hash computation")); } void WaitForExit(bool bDontWait = false) @@ -330,14 +360,15 @@ int _tmain(int argc, _TCHAR* argv[]) FILE* outputFile = NULL; bool bDontWait = false; bool bIncludeNames = false; + list excludeSpecList; setbuf (stdout, NULL); SetConsoleTitle(_T("DirHash by Mounir IDRASSI (mounir@idrix.fr) Copyright 2010-2015")); - _tprintf(_T("\nDirHash by Mounir IDRASSI (mounir@idrix.fr) Copyright 2010-2015\nRecursively compute hash of a given directory content in lexicographical order.\nIt can also compute the hash of a single file.\n\nSupported Algorithms : MD5, SHA1, SHA256, SHA384, SHA512\nUsing OpenSSL\n\n")); + _tprintf(_T("\nDirHash by Mounir IDRASSI (mounir@idrix.fr) Copyright 2010-2015\n\nRecursively compute hash of a given directory content in lexicographical order.\nIt can also compute the hash of a single file.\n\nSupported Algorithms : MD5, SHA1, SHA256, SHA384, SHA512\nUsing OpenSSL\n\n")); - if (argc < 2 || argc > 7) + if (argc < 2) { ShowUsage(); WaitForExit(); @@ -353,6 +384,7 @@ int _tmain(int argc, _TCHAR* argv[]) if ((i + 1) >= argc) { // missing file argument + _tprintf(_T("Error: Missing argument for switch -t\n\n")); ShowUsage(); WaitForExit(); return 1; @@ -376,12 +408,28 @@ int _tmain(int argc, _TCHAR* argv[]) { bIncludeNames = true; } + else if (_tcscmp(argv[i],_T("-exclude")) == 0) + { + if ((i + 1) >= argc) + { + // missing file argument + _tprintf(_T("Error: Missing argument for switch -exclude\n\n")); + ShowUsage(); + WaitForExit(); + return 1; + } + + excludeSpecList.push_back(argv[i+1]); + + i++; + } else { pHash = Hash::GetHash(argv[i]); if (!pHash) { if (outputFile) fclose(outputFile); + _tprintf(_T("Error: Argument \"%s\" not recognized\n\n"), argv[i]); ShowUsage(); WaitForExit(); return 1; @@ -402,7 +450,7 @@ int _tmain(int argc, _TCHAR* argv[]) { if (outputFile) fclose(outputFile); delete pHash; - _tprintf(TEXT("\nError: Directory path is too long. Maximum length is %d characters\n"), MAX_PATH); + _tprintf(TEXT("\nError: Input directory/file path is too long. Maximum length is %d characters\n"), MAX_PATH); WaitForExit(bDontWait); return (-1); } @@ -421,9 +469,25 @@ int _tmain(int argc, _TCHAR* argv[]) fflush(stdout); if (PathIsDirectory(argv[1])) - dwError = HashDirectory(argv[1], pHash, bIncludeNames); + { + // remove any trailing backslash to harmonize directory names in case they are included + // in hash computations + int pathLen = lstrlen(argv[1]); + TCHAR backslash = 0; + if (argv[1][pathLen - 1] == '\\' || argv[1][pathLen - 1] == '/') + { + backslash = argv[1][pathLen - 1]; + argv[1][pathLen - 1] = 0; + } + + dwError = HashDirectory(argv[1], pHash, bIncludeNames, excludeSpecList); + + // restore backslash + if (backslash) + argv[1][pathLen - 1] = backslash; + } else - dwError = HashFile(argv[1], pHash, bIncludeNames); + dwError = HashFile(argv[1], pHash, bIncludeNames, excludeSpecList); if (dwError == NO_ERROR) { diff --git a/DirHash.rc b/DirHash.rc index c919a9d..43b2dc2 100644 --- a/DirHash.rc +++ b/DirHash.rc @@ -53,8 +53,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,3,0,0 - PRODUCTVERSION 1,3,0,0 + FILEVERSION 1,4,0,0 + PRODUCTVERSION 1,4,0,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -72,12 +72,12 @@ BEGIN VALUE "Comments", "By Mounir IDRASSI" VALUE "CompanyName", "IDRIX" VALUE "FileDescription", "compute Hash of dorectories and files" - VALUE "FileVersion", "1, 3, 0, 0" + VALUE "FileVersion", "1, 4, 0, 0" VALUE "InternalName", "DirHash" VALUE "LegalCopyright", "Copyright (C) 2015 IDRIX" VALUE "OriginalFilename", "DirHash.exe" VALUE "ProductName", "DirHash Application" - VALUE "ProductVersion", "1, 3, 0, 0" + VALUE "ProductVersion", "1, 4, 0, 0" END END BLOCK "VarFileInfo" diff --git a/DirHash.sln b/DirHash.sln index 788a72f..099e7f9 100644 --- a/DirHash.sln +++ b/DirHash.sln @@ -6,13 +6,19 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {93AE07A1-5461-409F-A72C-449B42DFDFDD}.Debug|Win32.ActiveCfg = Debug|Win32 {93AE07A1-5461-409F-A72C-449B42DFDFDD}.Debug|Win32.Build.0 = Debug|Win32 + {93AE07A1-5461-409F-A72C-449B42DFDFDD}.Debug|x64.ActiveCfg = Debug|x64 + {93AE07A1-5461-409F-A72C-449B42DFDFDD}.Debug|x64.Build.0 = Debug|x64 {93AE07A1-5461-409F-A72C-449B42DFDFDD}.Release|Win32.ActiveCfg = Release|Win32 {93AE07A1-5461-409F-A72C-449B42DFDFDD}.Release|Win32.Build.0 = Release|Win32 + {93AE07A1-5461-409F-A72C-449B42DFDFDD}.Release|x64.ActiveCfg = Release|x64 + {93AE07A1-5461-409F-A72C-449B42DFDFDD}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/DirHash.vcxproj b/DirHash.vcxproj index 8b486b9..2823cfc 100644 --- a/DirHash.vcxproj +++ b/DirHash.vcxproj @@ -5,10 +5,18 @@ Debug Win32 + + Debug + x64 + Release Win32 + + Release + x64 + {93AE07A1-5461-409F-A72C-449B42DFDFDD} @@ -21,28 +29,49 @@ Unicode true + + Application + Unicode + true + Application Unicode + + Application + Unicode + + + + + + + <_ProjectFileVersion>10.0.40219.1 $(SolutionDir)$(Configuration)\ + $(SolutionDir)x64\$(Configuration)\ $(Configuration)\ + x64\$(Configuration)\ true + true $(SolutionDir)$(Configuration)\ + $(SolutionDir)x64\$(Configuration)\ $(Configuration)\ + x64\$(Configuration)\ false + false @@ -66,6 +95,26 @@ MachineX86 + + + Disabled + $(ProjectDir)openssl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + libeay64MTd.lib;Shlwapi.lib;%(AdditionalDependencies) + $(ProjectDir)openssl\lib;%(AdditionalLibraryDirectories) + %(IgnoreSpecificDefaultLibraries) + true + Console + + MaxSpeed @@ -90,6 +139,29 @@ MachineX86 + + + MaxSpeed + true + $(ProjectDir)openssl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level3 + + + + + libeay64MT.lib;Shlwapi.lib;%(AdditionalDependencies) + $(ProjectDir)openssl\lib;%(AdditionalLibraryDirectories) + false + Console + true + true + + diff --git a/openssl/lib/libeay64MT.lib b/openssl/lib/libeay64MT.lib new file mode 100644 index 0000000..2858070 Binary files /dev/null and b/openssl/lib/libeay64MT.lib differ diff --git a/openssl/lib/libeay64MTd.lib b/openssl/lib/libeay64MTd.lib new file mode 100644 index 0000000..28b5713 Binary files /dev/null and b/openssl/lib/libeay64MTd.lib differ