mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-07 11:14:58 -06:00
Update to 7-Zip Version 21.02
This commit is contained in:
367
CPP/7zip/UI/FileManager/VerCtrl.cpp
Normal file
367
CPP/7zip/UI/FileManager/VerCtrl.cpp
Normal file
@@ -0,0 +1,367 @@
|
||||
// VerCtrl.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../Common/StringToInt.h"
|
||||
|
||||
#include "../../../Windows/FileName.h"
|
||||
#include "../../../Windows/FileFind.h"
|
||||
|
||||
#include "App.h"
|
||||
#include "RegistryUtils.h"
|
||||
#include "OverwriteDialog.h"
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
using namespace NWindows;
|
||||
using namespace NFile;
|
||||
using namespace NFind;
|
||||
using namespace NDir;
|
||||
|
||||
static UString ConvertPath_to_Ctrl(const UString &path)
|
||||
{
|
||||
UString s = path;
|
||||
s.Replace(L':', L'_');
|
||||
return s;
|
||||
}
|
||||
|
||||
struct CFileDataInfo
|
||||
{
|
||||
CByteBuffer Data;
|
||||
BY_HANDLE_FILE_INFORMATION Info;
|
||||
bool IsOpen;
|
||||
|
||||
CFileDataInfo(): IsOpen (false) {}
|
||||
UInt64 GetSize() const { return (((UInt64)Info.nFileSizeHigh) << 32) + Info.nFileSizeLow; }
|
||||
bool Read(const UString &path);
|
||||
};
|
||||
|
||||
|
||||
bool CFileDataInfo::Read(const UString &path)
|
||||
{
|
||||
IsOpen = false;
|
||||
NIO::CInFile file;
|
||||
if (!file.Open(path))
|
||||
return false;
|
||||
if (!file.GetFileInformation(&Info))
|
||||
return false;
|
||||
|
||||
const UInt64 size = GetSize();
|
||||
const size_t size2 = (size_t)size;
|
||||
if (size2 != size || size2 > (1 << 28))
|
||||
{
|
||||
SetLastError(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
Data.Alloc(size2);
|
||||
|
||||
size_t processedSize;
|
||||
if (!file.ReadFull(Data, size2, processedSize))
|
||||
return false;
|
||||
if (processedSize != size2)
|
||||
{
|
||||
SetLastError(1);
|
||||
return false;
|
||||
}
|
||||
IsOpen = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool CreateComplexDir_for_File(const UString &path)
|
||||
{
|
||||
FString resDirPrefix;
|
||||
FString resFileName;
|
||||
if (!GetFullPathAndSplit(path, resDirPrefix, resFileName))
|
||||
return false;
|
||||
return CreateComplexDir(resDirPrefix);
|
||||
}
|
||||
|
||||
|
||||
static bool ParseNumberString(const FString &s, UInt32 &number)
|
||||
{
|
||||
const wchar_t *end;
|
||||
UInt64 result = ConvertStringToUInt64(s, &end);
|
||||
if (*end != 0 || s.IsEmpty() || result > (UInt32)0x7FFFFFFF)
|
||||
return false;
|
||||
number = (UInt32)result;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void WriteFile(const FString &path, bool createAlways, const CFileDataInfo &fdi, const CPanel &panel)
|
||||
{
|
||||
NIO::COutFile outFile;
|
||||
if (!outFile.Create(path, createAlways)) // (createAlways = false) means CREATE_NEW
|
||||
{
|
||||
panel.MessageBox_LastError();
|
||||
return;
|
||||
}
|
||||
UInt32 processedSize;
|
||||
if (!outFile.Write(fdi.Data, (UInt32)fdi.Data.Size(), processedSize))
|
||||
{
|
||||
panel.MessageBox_LastError();
|
||||
return;
|
||||
}
|
||||
if (processedSize != fdi.Data.Size())
|
||||
{
|
||||
panel.MessageBox_Error(L"Write error");
|
||||
return;
|
||||
}
|
||||
if (!outFile.SetTime(
|
||||
&fdi.Info.ftCreationTime,
|
||||
&fdi.Info.ftLastAccessTime,
|
||||
&fdi.Info.ftLastWriteTime))
|
||||
{
|
||||
panel.MessageBox_LastError();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!SetFileAttrib(path, fdi.Info.dwFileAttributes))
|
||||
{
|
||||
panel.MessageBox_LastError();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CApp::VerCtrl(unsigned id)
|
||||
{
|
||||
const CPanel &panel = GetFocusedPanel();
|
||||
|
||||
if (!panel.Is_IO_FS_Folder())
|
||||
{
|
||||
panel.MessageBox_Error_UnsupportOperation();
|
||||
return;
|
||||
}
|
||||
|
||||
CRecordVector<UInt32> indices;
|
||||
panel.GetSelectedItemsIndices(indices);
|
||||
|
||||
if (indices.Size() != 1)
|
||||
{
|
||||
// panel.MessageBox_Error_UnsupportOperation();
|
||||
return;
|
||||
}
|
||||
|
||||
const UString path = panel.GetItemFullPath(indices[0]);
|
||||
|
||||
UString vercPath;
|
||||
ReadReg_VerCtrlPath(vercPath);
|
||||
if (vercPath.IsEmpty())
|
||||
return;
|
||||
NName::NormalizeDirPathPrefix(vercPath);
|
||||
|
||||
FString dirPrefix;
|
||||
FString fileName;
|
||||
if (!GetFullPathAndSplit(path, dirPrefix, fileName))
|
||||
{
|
||||
panel.MessageBox_LastError();
|
||||
return;
|
||||
}
|
||||
|
||||
const UString dirPrefix2 = vercPath + ConvertPath_to_Ctrl(dirPrefix);
|
||||
const UString path2 = dirPrefix2 + fileName;
|
||||
|
||||
bool sameTime = false;
|
||||
bool sameData = false;
|
||||
bool areIdentical = false;
|
||||
|
||||
CFileDataInfo fdi, fdi2;
|
||||
if (!fdi.Read(path))
|
||||
{
|
||||
panel.MessageBox_LastError();
|
||||
return;
|
||||
}
|
||||
|
||||
if (fdi2.Read(path2))
|
||||
{
|
||||
sameData = (fdi.Data == fdi2.Data);
|
||||
sameTime = (CompareFileTime(&fdi.Info.ftLastWriteTime, &fdi2.Info.ftLastWriteTime) == 0);
|
||||
areIdentical = (sameData && sameTime);
|
||||
}
|
||||
|
||||
const bool isReadOnly = NAttributes::IsReadOnly(fdi.Info.dwFileAttributes);
|
||||
|
||||
if (id == IDM_VER_EDIT)
|
||||
{
|
||||
if (!isReadOnly)
|
||||
{
|
||||
panel.MessageBox_Error(L"File is not read-only");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!areIdentical)
|
||||
{
|
||||
if (fdi2.IsOpen)
|
||||
{
|
||||
NFind::CEnumerator enumerator;
|
||||
FString d2 = dirPrefix2;
|
||||
d2 += "_7vc";
|
||||
d2.Add_PathSepar();
|
||||
d2 += fileName;
|
||||
d2.Add_PathSepar();
|
||||
enumerator.SetDirPrefix(d2);
|
||||
NFind::CDirEntry fi;
|
||||
Int32 maxVal = -1;
|
||||
while (enumerator.Next(fi))
|
||||
{
|
||||
UInt32 val;
|
||||
if (!ParseNumberString(fi.Name, val))
|
||||
continue;
|
||||
if ((Int32)val > maxVal)
|
||||
maxVal = val;
|
||||
}
|
||||
|
||||
UInt32 next = (UInt32)maxVal + 1;
|
||||
if (maxVal < 0)
|
||||
{
|
||||
next = 1;
|
||||
if (!::CreateComplexDir_for_File(path2))
|
||||
{
|
||||
panel.MessageBox_LastError();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// we rename old file2 to some name;
|
||||
FString path_num = d2;
|
||||
{
|
||||
AString t;
|
||||
t.Add_UInt32((UInt32)next);
|
||||
while (t.Len() < 3)
|
||||
t.InsertAtFront('0');
|
||||
path_num += t;
|
||||
}
|
||||
|
||||
if (maxVal < 0)
|
||||
{
|
||||
if (!::CreateComplexDir_for_File(path_num))
|
||||
{
|
||||
panel.MessageBox_LastError();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!NDir::MyMoveFile(path2, path_num))
|
||||
{
|
||||
panel.MessageBox_LastError();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!::CreateComplexDir_for_File(path2))
|
||||
{
|
||||
panel.MessageBox_LastError();
|
||||
return;
|
||||
}
|
||||
}
|
||||
/*
|
||||
if (!::CopyFile(fs2fas(path), fs2fas(path2), TRUE))
|
||||
{
|
||||
panel.MessageBox_LastError();
|
||||
return;
|
||||
}
|
||||
*/
|
||||
WriteFile(path2,
|
||||
false, // (createAlways = false) means CREATE_NEW
|
||||
fdi, panel);
|
||||
}
|
||||
|
||||
if (!SetFileAttrib(path, fdi.Info.dwFileAttributes & ~(DWORD)FILE_ATTRIBUTE_READONLY))
|
||||
{
|
||||
panel.MessageBox_LastError();
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isReadOnly)
|
||||
{
|
||||
panel.MessageBox_Error(L"File is read-only");
|
||||
return;
|
||||
}
|
||||
|
||||
if (id == IDM_VER_COMMIT)
|
||||
{
|
||||
if (sameData)
|
||||
{
|
||||
if (!sameTime)
|
||||
{
|
||||
panel.MessageBox_Error(
|
||||
L"Same data, but different timestamps.\n"
|
||||
L"Use `Revert` to recover timestamp.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!SetFileAttrib(path, fdi.Info.dwFileAttributes | FILE_ATTRIBUTE_READONLY))
|
||||
{
|
||||
panel.MessageBox_LastError();
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (id == IDM_VER_REVERT)
|
||||
{
|
||||
if (!fdi2.IsOpen)
|
||||
{
|
||||
panel.MessageBox_Error(L"No file to revert");
|
||||
return;
|
||||
}
|
||||
if (!sameData || !sameTime)
|
||||
{
|
||||
if (!sameData)
|
||||
{
|
||||
/*
|
||||
UString m;
|
||||
m = "Are you sure you want to revert file ?";
|
||||
m.Add_LF();
|
||||
m += path;
|
||||
if (::MessageBoxW(panel.GetParent(), m, L"Version Control: File Revert", MB_OKCANCEL | MB_ICONQUESTION) != IDOK)
|
||||
return;
|
||||
*/
|
||||
COverwriteDialog dialog;
|
||||
|
||||
dialog.OldFileInfo.SetTime(&fdi.Info.ftLastWriteTime);
|
||||
dialog.OldFileInfo.SetSize(fdi.GetSize());
|
||||
dialog.OldFileInfo.Name = path;
|
||||
|
||||
dialog.NewFileInfo.SetTime(&fdi2.Info.ftLastWriteTime);
|
||||
dialog.NewFileInfo.SetSize(fdi2.GetSize());
|
||||
dialog.NewFileInfo.Name = path2;
|
||||
|
||||
dialog.ShowExtraButtons = false;
|
||||
dialog.DefaultButton_is_NO = true;
|
||||
|
||||
INT_PTR writeAnswer = dialog.Create(panel.GetParent());
|
||||
|
||||
if (writeAnswer != IDYES)
|
||||
return;
|
||||
}
|
||||
|
||||
WriteFile(path,
|
||||
true, // (createAlways = true) means CREATE_ALWAYS
|
||||
fdi2, panel);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!SetFileAttrib(path, fdi2.Info.dwFileAttributes | FILE_ATTRIBUTE_READONLY))
|
||||
{
|
||||
panel.MessageBox_LastError();
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// if (id == IDM_VER_DIFF)
|
||||
{
|
||||
if (!fdi2.IsOpen)
|
||||
return;
|
||||
DiffFiles(path2, path);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user