From 02d6107c97b48888362e7c6a70dcac323c89d741 Mon Sep 17 00:00:00 2001 From: Tomas Bzatek Date: Sun, 17 Dec 2023 21:23:58 +0100 Subject: ZipArchive: Update to the 4.6.9 release --- zip/ZipArchive/ZipPlatform_win.cpp | 394 +++++++++++++++++++++++++++---------- 1 file changed, 288 insertions(+), 106 deletions(-) (limited to 'zip/ZipArchive/ZipPlatform_win.cpp') diff --git a/zip/ZipArchive/ZipPlatform_win.cpp b/zip/ZipArchive/ZipPlatform_win.cpp index 6eb223f..bc7f962 100644 --- a/zip/ZipArchive/ZipPlatform_win.cpp +++ b/zip/ZipArchive/ZipPlatform_win.cpp @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// -// This source file is part of the ZipArchive library source distribution and -// is Copyrighted 2000 - 2007 by Artpol Software - Tadeusz Dracz +// This source file is part of the ZipArchive Library Open Source distribution +// and is Copyrighted 2000 - 2022 by Artpol Software - Tadeusz Dracz // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -9,16 +9,15 @@ // // For the licensing details refer to the License.txt file. // -// Web Site: http://www.artpol-software.com +// Web Site: https://www.artpol-software.com //////////////////////////////////////////////////////////////////////////////// -#include "_platform.h" +#include "stdafx.h" -#ifdef ZIP_ARCHIVE_WIN +#ifdef _ZIP_SYSTEM_WIN -#define ZIP_USES_SAFE_WINDOWS_API +#define _ZIP_SAFE_WINDOWS_API -#include "stdafx.h" #include "ZipPlatform.h" #include "ZipFileHeader.h" #include "ZipException.h" @@ -39,9 +38,15 @@ #define INVALID_FILE_ATTRIBUTES ((DWORD)-1) #endif +#ifndef INVALID_SET_FILE_POINTER + #define INVALID_SET_FILE_POINTER ((DWORD)-1) +#endif + #include #include +#include #include +#include #include "ZipPathComponent.h" #include "ZipCompatibility.h" @@ -80,7 +85,7 @@ CZipString ZipPlatform::GetTmpFileName(LPCTSTR lpszPath, ZIP_SIZE_TYPE uSizeNeed if (lpszPath) { tempPath = lpszPath; - bCheckTemp = GetDeviceFreeSpace(tempPath) < uSizeNeeded; + bCheckTemp = uSizeNeeded > 0 && GetDeviceFreeSpace(tempPath) < uSizeNeeded; } if (bCheckTemp) @@ -93,15 +98,29 @@ CZipString ZipPlatform::GetTmpFileName(LPCTSTR lpszPath, ZIP_SIZE_TYPE uSizeNeed tempPath.ReleaseBuffer(); if (GetDeviceFreeSpace(tempPath) < uSizeNeeded) { - if (!GetCurrentDirectory(tempPath) || GetDeviceFreeSpace(tempPath) < uSizeNeeded) + if (!GetCurrentDirectory(tempPath) || (uSizeNeeded > 0 && GetDeviceFreeSpace(tempPath) < uSizeNeeded)) return (CZipString)empty; } } - CZipString tempName; - if (!GetTempFileName(tempPath, _T("ZAR"), 0, tempName.GetBuffer(_MAX_PATH))) + CZipPathComponent::AppendSeparator(tempPath); + tempPath += _T("ZAR"); + tempPath += _T("XXXXXX"); + int length = tempPath.GetLength() + 1; +#if _MSC_VER >= 1400 + errno_t err = _tmktemp_s(tempPath.GetBuffer(length), (size_t)length); +#else // defined __MINGW32__ || _MSC_VER >= 1200 + LPTSTR err = _tmktemp(tempPath.GetBuffer(length)); +#endif + tempPath.ReleaseBuffer(); +#if _MSC_VER >= 1400 + if (err != 0) +#else + if (err == NULL) +#endif + { return (CZipString)empty; - tempName.ReleaseBuffer(); - return tempName; + } + return tempPath; } @@ -122,13 +141,12 @@ bool ZipPlatform::GetCurrentDirectory(CZipString& sz) bool ZipPlatform::SetFileAttr(LPCTSTR lpFileName, DWORD uAttr) { - return ::SetFileAttributes(lpFileName, uAttr) != 0; + return ::SetFileAttributes(CZipPathComponent::AddPrefix(lpFileName), uAttr) != 0; } bool ZipPlatform::GetFileAttr(LPCTSTR lpFileName, DWORD& uAttr) { - // not using MFC due to MFC bug (attr is one byte there) - DWORD temp = ::GetFileAttributes(lpFileName); + DWORD temp = ::GetFileAttributes(CZipPathComponent::AddPrefix(lpFileName)); if (temp == INVALID_FILE_ATTRIBUTES) return false; uAttr = temp; @@ -136,32 +154,124 @@ bool ZipPlatform::GetFileAttr(LPCTSTR lpFileName, DWORD& uAttr) } -bool ZipPlatform::GetFileModTime(LPCTSTR lpFileName, time_t & ttime) +bool ZipPlatform::GetFileTimes(LPCTSTR lpFileName, time_t* tModificationTime, time_t* tCreationTime, time_t* tLastAccessTime) { -#ifndef __BORLANDC__ - struct _stat st; - if (_tstat(lpFileName, &st) != 0) -#else - struct stat st; - if (stat(lpFileName, &st) != 0) -#endif - return false; - ttime = st.st_mtime; - if (ttime == (time_t)-1) + WIN32_FIND_DATA findData = {0}; + CZipString szPath = CZipPathComponent::AddPrefix(lpFileName); + HANDLE handle = ::FindFirstFile(szPath, &findData); + + if (tModificationTime != NULL) { - ttime = time(NULL); - return false; + *tModificationTime = 0; + } + if (tCreationTime != NULL) + { + *tCreationTime = 0; + } + if (tLastAccessTime != NULL) + { + *tLastAccessTime = 0; + } + bool ret = false; + if (handle != INVALID_HANDLE_VALUE) + { + FindClose(handle); + ret = true; } else - return true; + { + // handle the situation when there are no permissions for reading the list of files, but there are permissions for reading the file + handle = ::CreateFile(szPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (handle != INVALID_HANDLE_VALUE) + { + ZBOOL bResult = ::GetFileTime(handle, &findData.ftCreationTime, &findData.ftLastAccessTime, &findData.ftLastWriteTime); + CloseHandle(handle); + if (bResult != FALSE) + { + ret = true; + } + } + } + + if (ret) + { + if (tModificationTime != NULL && !ConvertFileTimeToTime(findData.ftLastWriteTime, *tModificationTime)) + ret = false; + if (tCreationTime != NULL && !ConvertFileTimeToTime(findData.ftCreationTime, *tCreationTime)) + ret = false; + if (tLastAccessTime != NULL && !ConvertFileTimeToTime(findData.ftLastAccessTime, *tLastAccessTime)) + ret = false; + } + + if (!ret) + { + time_t tNow = time(NULL); + if (tModificationTime != NULL && *tModificationTime <= 0) + { + *tModificationTime = tNow; + } + if (tCreationTime != NULL && *tCreationTime <= 0) + { + *tCreationTime = tNow; + } + if (tLastAccessTime != NULL && *tLastAccessTime <= 0) + { + *tLastAccessTime = tNow; + } + } + return ret; } -bool ZipPlatform::SetFileModTime(LPCTSTR lpFileName, time_t ttime) +bool ZipPlatform::SetFileTimes(LPCTSTR lpFileName, const time_t* tModificationTime, const time_t* tCreationTime, const time_t* tLastAccessTime) { - struct _utimbuf ub; - ub.actime = time(NULL); - ub.modtime = ttime == -1 ? time(NULL) : ttime; // if wrong file time, set it to the current - return _tutime(lpFileName, &ub) == 0; + HANDLE handle = ::CreateFile(CZipPathComponent::AddPrefix(lpFileName), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); + if (handle == INVALID_HANDLE_VALUE) + { + return false; + } + bool ret = ZipPlatform::SetFileTimes(handle, tModificationTime, tCreationTime, tLastAccessTime); + CloseHandle(handle); + return ret; +} + + +bool ZipPlatform::SetFileTimes(HANDLE handle, const time_t* tModificationTime, const time_t* tCreationTime, const time_t* tLastAccessTime) +{ + ZFILETIME ftModTime = {0}; + ZFILETIME* pftModTime; + if (tModificationTime != NULL) + { + ZipPlatform::ConvertTimeToFileTime(*tModificationTime, ftModTime); + pftModTime = &ftModTime; + } + else + { + pftModTime = NULL; + } + ZFILETIME ftCreationTime = {0}; + ZFILETIME* pftCreationTime; + if (tCreationTime != NULL) + { + ZipPlatform::ConvertTimeToFileTime(*tCreationTime, ftCreationTime); + pftCreationTime = &ftCreationTime; + } + else + { + pftCreationTime = NULL; + } + ZFILETIME ftLastAccessTime = {0}; + ZFILETIME* pftLastAccessTime; + if (tLastAccessTime != NULL) + { + ZipPlatform::ConvertTimeToFileTime(*tLastAccessTime, ftLastAccessTime); + pftLastAccessTime = &ftLastAccessTime; + } + else + { + pftLastAccessTime = NULL; + } + + return ::SetFileTime(handle, pftCreationTime, pftLastAccessTime , pftModTime) != 0; } bool ZipPlatform::ChangeDirectory(LPCTSTR lpDirectory) @@ -171,27 +281,10 @@ bool ZipPlatform::ChangeDirectory(LPCTSTR lpDirectory) int ZipPlatform::FileExists(LPCTSTR lpszName) { -#ifndef __BORLANDC__ - #if _MSC_VER >= 1400 - if (_taccess_s(lpszName, 0) == 0) - #else - if (_taccess(lpszName, 0) == 0) - #endif -#else - #ifdef _UNICODE - if (_waccess(lpszName, 0) == 0) - #else - if (access(lpszName, 0) == 0) - #endif -#endif - { - if (DirectoryExists(lpszName)) - return -1; - return 1; - } - else + DWORD attributes = ::GetFileAttributes(CZipPathComponent::AddPrefix(lpszName)); + if (attributes == INVALID_FILE_ATTRIBUTES) return 0; - + return ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) ? -1 : 1; } ZIPINLINE bool ZipPlatform::IsDriveRemovable(LPCTSTR lpszFilePath) @@ -210,7 +303,7 @@ ZIPINLINE bool ZipPlatform::SetVolLabel(LPCTSTR lpszPath, LPCTSTR lpszLabel) ZIPINLINE void ZipPlatform::AnsiOem(CZipAutoBuffer& buffer, bool bAnsiToOem) { -#ifdef ZIP_USES_SAFE_WINDOWS_API +#ifdef _ZIP_SAFE_WINDOWS_API UINT cpIn, cpOut; if (bAnsiToOem) { @@ -227,42 +320,96 @@ ZIPINLINE void ZipPlatform::AnsiOem(CZipAutoBuffer& buffer, bool bAnsiToOem) int size = buffer.GetSize(); // iLen doesn't include terminating character - int iLen = MultiByteToWideChar(cpIn, MB_PRECOMPOSED, buffer, size, NULL, 0); + int iLen = ::MultiByteToWideChar(cpIn, MB_PRECOMPOSED, buffer, size, NULL, 0); if (iLen <= 0) return; interBuffer.Allocate(iLen * sizeof(wchar_t)); LPWSTR lpszWide = (LPWSTR)(char*)interBuffer; - iLen = MultiByteToWideChar(cpIn, MB_PRECOMPOSED, buffer, size, lpszWide, iLen); + iLen = ::MultiByteToWideChar(cpIn, MB_PRECOMPOSED, buffer, size, lpszWide, iLen); ASSERT(iLen != 0); // iLen does not include terminating character - size = WideCharToMultiByte(cpOut, 0, lpszWide, iLen, NULL, 0, NULL, NULL); + size = ::WideCharToMultiByte(cpOut, 0, lpszWide, iLen, NULL, 0, NULL, NULL); if (size <= 0) return; buffer.Allocate(size); - size = WideCharToMultiByte(cpOut, 0, lpszWide, iLen, buffer, size, NULL, NULL); + size = ::WideCharToMultiByte(cpOut, 0, lpszWide, iLen, buffer, size, NULL, NULL); ASSERT(size != 0); #else if (bAnsiToOem) - CharToOemBuffA(buffer, buffer, buffer.GetSize()); + ::CharToOemBuffA(buffer, buffer, buffer.GetSize()); else - OemToCharBuffA(buffer, buffer, buffer.GetSize()); + ::OemToCharBuffA(buffer, buffer, buffer.GetSize()); #endif } -ZIPINLINE bool ZipPlatform::RemoveFile(LPCTSTR lpszFileName, bool bThrow) +ZIPINLINE bool ZipPlatform::RemoveFile(LPCTSTR lpszFileName, bool bThrow, int iMode) { - if (!::DeleteFile((LPTSTR)lpszFileName)) - if (bThrow) - CZipException::Throw(CZipException::notRemoved, lpszFileName); - else - return false; - return true; - + if ((iMode & ZipPlatform::fomRemoveReadOnly) != 0) + { + DWORD attr; + if (ZipPlatform::GetFileAttr(lpszFileName, attr) + && (ZipCompatibility::GetAsInternalAttributes(attr, ZipPlatform::GetSystemID()) & ZipCompatibility::attROnly) != 0) + { + ZipPlatform::SetFileAttr(lpszFileName, ZipPlatform::GetDefaultAttributes()); + } + } +#ifdef SHFileOperation + if ((iMode & ZipPlatform::fomRecycleBin) == 0) + { +#endif + if (::DeleteFile((LPTSTR)(LPCTSTR)CZipPathComponent::AddPrefix(lpszFileName, false))) + return true; +#ifdef SHFileOperation + } + else + { + CZipString file = lpszFileName; +#if defined _UNICODE && _MSC_VER >= 1400 + if (file.GetLength() >= MAX_PATH) + { + // cannot prefix for SHFileOperation, use short path + CZipString temp = CZipPathComponent::AddPrefix(lpszFileName, false); + DWORD size = ::GetShortPathName(temp, NULL, 0); + if (size != 0) + { + size = ::GetShortPathName(temp, file.GetBuffer(size), size); + file.ReleaseBuffer(); + } + if (size == 0) + { + if (bThrow) + CZipException::Throw(CZipException::notRemoved, lpszFileName); + return false; + } + // GetShortPathName keeps the prefix - remove it + int prefixLength = CZipPathComponent::IsPrefixed(file); + if (prefixLength > 0) + { + file = file.Mid(prefixLength); + } + } +#endif + int length = file.GetLength(); + CZipAutoBuffer buffer((length + 2) * sizeof(TCHAR), true); // double NULL is required + memcpy(buffer, (LPCTSTR)file, length * sizeof(TCHAR)); + SHFILEOPSTRUCT shFileOp = {0}; + shFileOp.wFunc = FO_DELETE; + shFileOp.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI; + shFileOp.pFrom = (LPCTSTR)(char*)buffer; + if (SHFileOperation(&shFileOp) == 0 && !shFileOp.fAnyOperationsAborted) + return true; + } +#endif + if (bThrow) + CZipException::Throw(CZipException::notRemoved, lpszFileName); + return false; } + ZIPINLINE bool ZipPlatform::RenameFile( LPCTSTR lpszOldName, LPCTSTR lpszNewName, bool bThrow) { - if (!::MoveFile((LPTSTR)lpszOldName, (LPTSTR)lpszNewName)) + if (!::MoveFile((LPTSTR)(LPCTSTR)CZipPathComponent::AddPrefix(lpszOldName, false), + (LPTSTR)(LPCTSTR)CZipPathComponent::AddPrefix(lpszNewName, false))) if (bThrow) CZipException::Throw(CZipException::notRenamed, lpszOldName); else @@ -276,9 +423,9 @@ ZIPINLINE bool ZipPlatform::IsDirectory(DWORD uAttr) return (uAttr & FILE_ATTRIBUTE_DIRECTORY) != 0; } -ZIPINLINE bool ZipPlatform::CreateDirectory(LPCTSTR lpDirectory) +ZIPINLINE bool ZipPlatform::CreateNewDirectory(LPCTSTR lpDirectory) { - return ::CreateDirectory(lpDirectory, NULL) != 0; + return ::CreateDirectory(CZipPathComponent::AddPrefix(lpDirectory), NULL) != 0; } ZIPINLINE DWORD ZipPlatform::GetDefaultAttributes() @@ -301,8 +448,14 @@ ZIPINLINE bool ZipPlatform::GetSystemCaseSensitivity() return false; } -#ifdef _UNICODE -int ZipPlatform::WideToMultiByte(LPCWSTR lpszIn, CZipAutoBuffer &szOut, UINT uCodePage) + +#ifdef _UNICODE + +#ifdef _ZIP_UNICODE_NORMALIZE + #pragma comment(lib, "Normaliz.lib") +#endif + +int ZipPlatform::WideToMultiByte(LPCWSTR lpszIn, CZipAutoBuffer &szOut, bool bAddNull, UINT uCodePage) { size_t wideLen = wcslen(lpszIn); if (wideLen == 0) @@ -312,46 +465,79 @@ int ZipPlatform::WideToMultiByte(LPCWSTR lpszIn, CZipAutoBuffer &szOut, UINT uCo } // iLen does not include terminating character - int iLen = WideCharToMultiByte(uCodePage, 0, lpszIn, (int)wideLen, szOut, + int iLen = ::WideCharToMultiByte(uCodePage, 0, lpszIn, (int)wideLen, szOut, 0, NULL, NULL); if (iLen > 0) { - szOut.Allocate(iLen, true); - iLen = WideCharToMultiByte(uCodePage, 0, lpszIn , (int)wideLen, szOut, + szOut.Allocate(bAddNull ? iLen + 1 : iLen, true); + iLen = ::WideCharToMultiByte(uCodePage, 0, lpszIn, (int)wideLen, szOut, iLen, NULL, NULL); - ASSERT(iLen != 0); + ASSERT(iLen > 0); + if (bAddNull) + { + szOut[iLen] = 0; + } + return iLen > 0 ? iLen : -1; } else // here it means error { szOut.Release(); - iLen --; + return -1; } - return iLen; - } -int ZipPlatform::MultiByteToWide(const CZipAutoBuffer &szIn, CZipString& szOut, UINT uCodePage) -{ - int singleLen = szIn.GetSize(); +int ZipPlatform::MultiByteToWide(const char* szIn, int iInSize, CZipString& szOut, UINT uCodePage) +{ + szOut.Empty(); + if (iInSize < 0) + { + iInSize = (int)std::string(szIn).length(); + } + if (iInSize == 0) + { + return 0; + } + // iLen doesn't include terminating character DWORD dwFlags = uCodePage <= CP_OEMCP ? MB_PRECOMPOSED : 0; - int iLen = MultiByteToWideChar(uCodePage, dwFlags, szIn.GetBuffer(), singleLen, NULL, 0); + int iLen = ::MultiByteToWideChar(uCodePage, dwFlags, szIn, iInSize, NULL, 0); if (iLen > 0) { - iLen = MultiByteToWideChar(uCodePage, dwFlags, szIn.GetBuffer(), singleLen, - szOut.GetBuffer(iLen) , iLen); + iLen = ::MultiByteToWideChar(uCodePage, dwFlags, szIn, iInSize, szOut.GetBuffer(iLen), iLen); szOut.ReleaseBuffer(iLen); - ASSERT(iLen != 0); + ASSERT(iLen > 0); + if (iLen == 0) + return -1; +#ifdef _ZIP_UNICODE_NORMALIZE + // if there is a problem with compilation here, you may need uncomment the block defining WINVER = 0x0600 at the bottom of _features.h file + if (::IsNormalizedString(NormalizationC, szOut, iLen + 1) != FALSE) + return iLen; + int iNewLen = ::NormalizeString(NormalizationC, szOut, iLen, NULL, 0); + if (iNewLen <= 0) + { + return iLen; + } + CZipString szNormalized; + iNewLen = ::NormalizeString(NormalizationC, szOut, iLen, szNormalized.GetBuffer(iNewLen), iNewLen); + if (iNewLen <= 0) + { + szNormalized.ReleaseBuffer(0); + return iLen; + } + szNormalized.ReleaseBuffer(iNewLen); + szOut = szNormalized; + return iNewLen; +#else + return iLen; +#endif } else - { - szOut.Empty(); - iLen --; // return -1 - } - return iLen; + { + return -1; + } } #endif -#if defined ZIP_ARCHIVE_STL || defined ZIP_FILE_USES_STL +#if defined _ZIP_IMPL_STL || _ZIP_FILE_IMPLEMENTATION == ZIP_ZFI_STL #if _MSC_VER > 1000 #pragma warning( push ) @@ -359,26 +545,22 @@ int ZipPlatform::MultiByteToWide(const CZipAutoBuffer &szIn, CZipString& szOut, #endif -#include -#include bool ZipPlatform::TruncateFile(int iDes, ULONGLONG uSize) { #if (_MSC_VER >= 1400) return _chsize_s(iDes, uSize) == 0; #else - if (uSize <= LONG_MAX) - return chsize(iDes, (LONG)uSize) == 0; - else if (uSize > _I64_MAX) + if (uSize > _I64_MAX) CZipException::Throw(CZipException::tooBigSize); else { HANDLE handle = (HANDLE)GetFileSystemHandle(iDes); ULARGE_INTEGER li; li.QuadPart = uSize; - li.LowPart = SetFilePointer(handle, li.LowPart, (LONG*)&li.HighPart, FILE_BEGIN); - if (li.LowPart == UINT_MAX && GetLastError() != NO_ERROR) + li.LowPart = ::SetFilePointer(handle, li.LowPart, (LONG*)&li.HighPart, FILE_BEGIN); + if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) return false; - return SetEndOfFile(handle) != 0; + return ::SetEndOfFile(handle) != FALSE; } return false; // for the compiler #endif @@ -394,7 +576,7 @@ int ZipPlatform::OpenFile(LPCTSTR lpszFileName, UINT iMode, int iShareMode) { switch (iShareMode) { - case (CZipFile::shareDenyWrite & CZipFile::shareDenyRead): + case (CZipFile::shareExclusive): iShareMode = SH_DENYRW; break; case (CZipFile::shareDenyRead): @@ -429,6 +611,6 @@ intptr_t ZipPlatform::GetFileSystemHandle(int iDes) } -#endif // ZIP_ARCHIVE_STL +#endif // _ZIP_IMPL_STL -#endif // ZIP_ARCHIVE_WIN +#endif // _ZIP_SYSTEM_WIN -- cgit v1.2.3