Fix bug 62427

CFileBinary::GetTime,
CFileBinary::SetTime was updated
Fix bugs with time in Zip/Unzip
This commit is contained in:
Alexey
2024-01-21 23:11:32 +03:00
parent 5c18827224
commit bc4449f7a7
4 changed files with 203 additions and 57 deletions

View File

@ -43,6 +43,8 @@
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <utime.h>
#endif
#ifdef _MAC
@ -1688,38 +1690,161 @@ namespace NSFile
g_overrideTmpPath = strTempPath;
}
unsigned long CFileBinary::GetDateTime(const std::wstring & inputFile)
bool CFileBinary::GetTime(const std::wstring& sFilename, struct tm* ptmLastWrite, struct tm* ptmLastAccess)
{
unsigned long result = 0;
#if defined(_WIN32) || defined (_WIN64)
bool result = true;
if (ptmLastWrite) memset(ptmLastWrite, 0, sizeof(struct tm));
if (ptmLastAccess) memset(ptmLastAccess, 0, sizeof(struct tm));
#if defined(_WIN32) || defined (_WIN64) // windows
HANDLE hFile;
hFile = ::CreateFileW(inputFile.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
hFile = ::CreateFileW(sFilename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile)
{
FILETIME ft; ft.dwLowDateTime = ft.dwHighDateTime = 0;
if (GetFileTime(hFile, NULL, NULL, &ft))
FILETIME ftLastWrite{}, ftLastAccess{};
if (::GetFileTime(hFile, NULL, &ftLastAccess, &ftLastWrite))
{
WORD fatDate = 0, fatTime = 0;
if (FileTimeToDosDateTime(&ft, &fatDate, &fatTime))
FILETIME ftLastWriteLocal{}, ftLastAccessLocal{};
result = result && ::FileTimeToLocalFileTime(&ftLastWrite, &ftLastWriteLocal);
result = result && ::FileTimeToLocalFileTime(&ftLastAccess, &ftLastAccessLocal);
SYSTEMTIME stLastWrite{}, stLastAccess{};
result = result && ::FileTimeToSystemTime(&ftLastWriteLocal, &stLastWrite);
result = result && ::FileTimeToSystemTime(&ftLastAccessLocal, &stLastAccess);
auto set_tm_by_st = [] (struct tm* time_tm, SYSTEMTIME* time_st) {
time_tm->tm_sec = static_cast<int>(time_st->wSecond);
time_tm->tm_min = static_cast<int>(time_st->wMinute);
time_tm->tm_hour = static_cast<int>(time_st->wHour);
time_tm->tm_mday = static_cast<int>(time_st->wDay);
time_tm->tm_mon = static_cast<int>(time_st->wMonth);
time_tm->tm_year = static_cast<int>(time_st->wYear);
};
if (result)
{
result = (fatDate << 16) + fatTime;
if (ptmLastWrite) set_tm_by_st(ptmLastWrite, &stLastWrite);
if (ptmLastAccess) set_tm_by_st(ptmLastAccess, &stLastAccess);
}
}
else
result = false;
CloseHandle(hFile);
}
#else
std::string inputFileA = U_TO_UTF8(inputFile);
#if defined(__linux__) && !defined(_MAC)
struct stat attrib;
stat(inputFileA.c_str(), &attrib);
result = attrib.st_mtim.tv_nsec;
#else
struct stat attrib;
stat(inputFileA.c_str(), &attrib);
result = (unsigned long)attrib.st_mtimespec.tv_nsec;
#endif
#endif
else
result = false;
#else // linux or macOS
struct stat attr;
result = (0 == stat(U_TO_UTF8(sFilename).c_str(), &attr));
if (result)
{
auto set_tm_by_secs = [] (struct tm* time_tm, time_t time_secs) {
struct tm* ltime = localtime(&time_secs);
*time_tm = *ltime;
time_tm->tm_year += 1900;
time_tm->tm_mon += 1;
};
time_t m_secs = attr.st_mtim.tv_sec; // edit
time_t a_secs = attr.st_atim.tv_sec; // access
if (ptmLastWrite) set_tm_by_secs(ptmLastWrite, m_secs);
if (ptmLastAccess) set_tm_by_secs(ptmLastAccess, a_secs);
}
#endif // defined(_WIN32) || defined (_WIN64)
return result;
}
bool CFileBinary::SetTime(const std::wstring& sFilename, struct tm* ptmLastWrite, struct tm* ptmLastAccess)
{
bool result = true;
#if defined(_WIN32) || defined (_WIN64) // windows
auto set_st_by_tm = [] (SYSTEMTIME* time_st, struct tm* time_tm) {
time_st->wSecond = static_cast<WORD>(time_tm->tm_sec);
time_st->wMinute = static_cast<WORD>(time_tm->tm_min);
time_st->wHour = static_cast<WORD>(time_tm->tm_hour);
time_st->wDay = static_cast<WORD>(time_tm->tm_mday);
time_st->wMonth = static_cast<WORD>(time_tm->tm_mon);
time_st->wYear = static_cast<WORD>(time_tm->tm_year);
};
SYSTEMTIME stLastWrite{}, stLastAccess{};
if (ptmLastWrite) set_st_by_tm(&stLastWrite, ptmLastWrite);
if (ptmLastAccess) set_st_by_tm(&stLastAccess, ptmLastAccess);
FILETIME ftLastWriteLocal{}, ftLastAccessLocal{};
if (ptmLastWrite) result = result && ::SystemTimeToFileTime(&stLastWrite, &ftLastWriteLocal);
if (ptmLastAccess) result = result && ::SystemTimeToFileTime(&stLastAccess, &ftLastAccessLocal);
FILETIME ftLastWrite{}, ftLastAccess{};
if (ptmLastWrite) result = result && ::LocalFileTimeToFileTime(&ftLastWriteLocal, &ftLastWrite);
if (ptmLastAccess) result = result && ::LocalFileTimeToFileTime(&ftLastAccessLocal, &ftLastAccess);
if (result)
{
HANDLE hFile;
hFile = ::CreateFileW(sFilename.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile)
{
FILETIME* pftLastWrite = NULL;
FILETIME* pftLastAccess = NULL;
if (ptmLastWrite) pftLastWrite = &ftLastWrite;
if (ptmLastAccess) pftLastAccess = &ftLastAccess;
result = SetFileTime(hFile, NULL, pftLastAccess, pftLastWrite);
}
else
result = false;
CloseHandle(hFile);
}
#else // linux or macOS
struct stat attr;
std::string sFilenameA = U_TO_UTF8(sFilename);
result = (0 == stat(sFilenameA.c_str(), &attr));
if (result)
{
time_t m_secs = attr.st_mtim.tv_sec; // edit
time_t a_secs = attr.st_atim.tv_sec; // access
time_t new_m_secs = m_secs;
time_t new_a_secs = a_secs;
if (ptmLastWrite)
{
struct tm tmLastWriteUnix = *ptmLastWrite;
tmLastWriteUnix.tm_year -= 1900;
tmLastWriteUnix.tm_mon -= 1;
new_m_secs = mktime(&tmLastWriteUnix);
}
if (ptmLastAccess)
{
struct tm tmLastAccessUnix = *ptmLastAccess;
tmLastAccessUnix.tm_year -= 1900;
tmLastAccessUnix.tm_mon -= 1;
new_a_secs = mktime(&tmLastAccessUnix);
}
utimbuf new_time{};
new_time.actime = new_a_secs;
new_time.modtime = new_m_secs;
utime(sFilenameA.c_str(), &new_time);
}
#endif // defined(_WIN32) || defined (_WIN64)
return result;
}
}

View File

@ -194,7 +194,18 @@ namespace NSFile
static bool OpenTempFile(std::wstring *pwsName, FILE **ppFile, wchar_t *wsMode, wchar_t *wsExt, wchar_t *wsFolder, wchar_t* wsName = NULL);
static FILE* OpenFileNative(const std::wstring& sFileName, const std::wstring& sMode);
static unsigned long GetDateTime(const std::wstring & strFileName);
// returns true if everything is OK;
// you can set ptmLastWrite / ptmLastAccess to nullptr if you are not going to use them;
// tm_wday && tm_yday && tm_isdst is unused on windows
static bool GetTime(const std::wstring& sFilename,
struct tm* ptmLastWrite = nullptr,
struct tm* ptmLastAccess = nullptr);
// returns true if everything is OK;
// you can set ptmLastWrite / ptmLastAccess to nullptr if you are not going to change them
static bool SetTime(const std::wstring& sFilename,
struct tm* ptmLastWrite = nullptr,
struct tm* ptmLastAccess = nullptr);
};
class KERNEL_DECL CBase64Converter

View File

@ -53,7 +53,7 @@ public:
HRESULT ExtractToDirectory (const std::wstring& zipFile, const std::wstring& unzipDir, wchar_t* password, short extract_without_path);
HRESULT ExtractToDirectory (BYTE* data, size_t len, const std::wstring& unzipDir, wchar_t* password, short extract_without_path);
HRESULT CompressFileOrDirectory (const std::wstring& name, const std::wstring& outputFile, bool bSorted = false, int method = Z_DEFLATED, short level = -1, bool bDateTime = false);
HRESULT CompressFileOrDirectory (const std::wstring& name, const std::wstring& outputFile, bool bSorted = false, int method = Z_DEFLATED, short level = -1, bool bDateTime = true);
HRESULT Uncompress (BYTE* destBuf, ULONG* destSize, BYTE* sourceBuf, ULONG sourceSize);
HRESULT Compress (BYTE* destBuf, ULONG* destSize, BYTE* sourceBuf, ULONG sourceSize, short level = -1);

View File

@ -217,28 +217,6 @@ namespace ZLibZipUtils
/*========================================================================================================*/
/* change_file_date : change the date/time of a file
filename : the filename of the file where date/time must be modified
dosdate : the new date at the MSDos format (4 bytes)
tmu_date : the SAME new date at the tm_unz format */
static void change_file_date( const wchar_t *filename, uLong dosdate, tm_unz tmu_date )
{
#if defined(_WIN32) || defined (_WIN64)
HANDLE hFile;
FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite;
hFile = CreateFileW(filename,GENERIC_READ | GENERIC_WRITE,
0,NULL,OPEN_EXISTING,0,NULL);
GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite);
DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal);
LocalFileTimeToFileTime(&ftLocal,&ftm);
SetFileTime(hFile,&ftm,&ftLastAcc,&ftm);
CloseHandle(hFile);
#endif
}
/*========================================================================================================*/
static void replace_all(std::string& subject, const std::string& search, const std::string& replace)
{
size_t pos = 0;
@ -380,13 +358,22 @@ namespace ZLibZipUtils
break;
}
}
// ?
while (err>0);
//close вызовется в oFile
if (err==0)
{
change_file_date(write_filename, file_info.dosDate, file_info.tmu_date);
oFile.CloseFile();
struct tm time;
memset(&time, 0, sizeof(struct tm));
time.tm_sec = file_info.tmu_date.tm_sec;
time.tm_min = file_info.tmu_date.tm_min;
time.tm_hour = file_info.tmu_date.tm_hour;
time.tm_mday = file_info.tmu_date.tm_mday;
time.tm_mon = file_info.tmu_date.tm_mon + 1;
time.tm_year = file_info.tmu_date.tm_year;
NSFile::CFileBinary::SetTime(write_filename, &time);
}
}
@ -568,16 +555,24 @@ namespace ZLibZipUtils
zip_fileinfo zinfo;
zinfo.dosDate = zinfo.external_fa = zinfo.internal_fa = 0;
zinfo.tmz_date.tm_sec = zinfo.tmz_date.tm_min = zinfo.tmz_date.tm_hour = 0;
zinfo.tmz_date.tm_mday = 1;
zinfo.tmz_date.tm_mon = 0;
zinfo.tmz_date.tm_year = 1980;
zip_fileinfo* zi_new = zi ? zi : &zinfo;
if (bDateTime )
if (bDateTime)
{
zi_new->dosDate = oFile.GetDateTime(file_name);
struct tm edited;
bool ok = NSFile::CFileBinary::GetTime(file_name, &edited);
if (ok)
{
zi_new->tmz_date.tm_sec = edited.tm_sec;
zi_new->tmz_date.tm_min = edited.tm_min;
zi_new->tmz_date.tm_hour = edited.tm_hour;
zi_new->tmz_date.tm_mday = edited.tm_mday;
zi_new->tmz_date.tm_mon = edited.tm_mon - 1;
zi_new->tmz_date.tm_year = edited.tm_year;
}
}
if(oFile.OpenFile(file_name))
{
DWORD dwSizeRead;
@ -726,9 +721,24 @@ namespace ZLibZipUtils
zip_fileinfo zinfo;
zinfo.external_fa = zinfo.internal_fa = 0;
zinfo.dosDate = bDateTime ? oFile.GetDateTime(inputFile) : 0;
zinfo.dosDate = 0;
if(oFile.OpenFile(inputFile))
if (bDateTime)
{
struct tm edited;
bool ok = NSFile::CFileBinary::GetTime(inputFile, &edited);
if (ok)
{
zinfo.tmz_date.tm_sec = edited.tm_sec;
zinfo.tmz_date.tm_min = edited.tm_min;
zinfo.tmz_date.tm_hour = edited.tm_hour;
zinfo.tmz_date.tm_mday = edited.tm_mday;
zinfo.tmz_date.tm_mon = edited.tm_mon - 1;
zinfo.tmz_date.tm_year = edited.tm_year;
}
}
if (oFile.OpenFile(inputFile))
{
DWORD dwSizeRead;
BYTE* pData = new BYTE[oFile.GetFileSize()];