xref: /aosp_15_r20/external/lzma/CPP/7zip/UI/FileManager/VerCtrl.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // VerCtrl.cpp
2*f6dc9357SAndroid Build Coastguard Worker 
3*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
4*f6dc9357SAndroid Build Coastguard Worker 
5*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/StringToInt.h"
6*f6dc9357SAndroid Build Coastguard Worker 
7*f6dc9357SAndroid Build Coastguard Worker #include "../../../Windows/FileName.h"
8*f6dc9357SAndroid Build Coastguard Worker #include "../../../Windows/FileFind.h"
9*f6dc9357SAndroid Build Coastguard Worker 
10*f6dc9357SAndroid Build Coastguard Worker #include "App.h"
11*f6dc9357SAndroid Build Coastguard Worker #include "RegistryUtils.h"
12*f6dc9357SAndroid Build Coastguard Worker #include "OverwriteDialog.h"
13*f6dc9357SAndroid Build Coastguard Worker 
14*f6dc9357SAndroid Build Coastguard Worker #include "resource.h"
15*f6dc9357SAndroid Build Coastguard Worker 
16*f6dc9357SAndroid Build Coastguard Worker using namespace NWindows;
17*f6dc9357SAndroid Build Coastguard Worker using namespace NFile;
18*f6dc9357SAndroid Build Coastguard Worker using namespace NFind;
19*f6dc9357SAndroid Build Coastguard Worker using namespace NDir;
20*f6dc9357SAndroid Build Coastguard Worker 
ConvertPath_to_Ctrl(const FString & path)21*f6dc9357SAndroid Build Coastguard Worker static FString ConvertPath_to_Ctrl(const FString &path)
22*f6dc9357SAndroid Build Coastguard Worker {
23*f6dc9357SAndroid Build Coastguard Worker   FString s = path;
24*f6dc9357SAndroid Build Coastguard Worker   s.Replace(FChar(':'), FChar('_'));
25*f6dc9357SAndroid Build Coastguard Worker   return s;
26*f6dc9357SAndroid Build Coastguard Worker }
27*f6dc9357SAndroid Build Coastguard Worker 
28*f6dc9357SAndroid Build Coastguard Worker struct CFileDataInfo
29*f6dc9357SAndroid Build Coastguard Worker {
30*f6dc9357SAndroid Build Coastguard Worker   CByteBuffer Data;
31*f6dc9357SAndroid Build Coastguard Worker   BY_HANDLE_FILE_INFORMATION Info;
32*f6dc9357SAndroid Build Coastguard Worker   bool IsOpen;
33*f6dc9357SAndroid Build Coastguard Worker 
CFileDataInfoCFileDataInfo34*f6dc9357SAndroid Build Coastguard Worker   CFileDataInfo(): IsOpen (false) {}
GetSizeCFileDataInfo35*f6dc9357SAndroid Build Coastguard Worker   UInt64 GetSize() const { return (((UInt64)Info.nFileSizeHigh) << 32) + Info.nFileSizeLow; }
36*f6dc9357SAndroid Build Coastguard Worker   bool Read(const FString &path);
37*f6dc9357SAndroid Build Coastguard Worker };
38*f6dc9357SAndroid Build Coastguard Worker 
39*f6dc9357SAndroid Build Coastguard Worker 
Read(const FString & path)40*f6dc9357SAndroid Build Coastguard Worker bool CFileDataInfo::Read(const FString &path)
41*f6dc9357SAndroid Build Coastguard Worker {
42*f6dc9357SAndroid Build Coastguard Worker   IsOpen = false;
43*f6dc9357SAndroid Build Coastguard Worker   NIO::CInFile file;
44*f6dc9357SAndroid Build Coastguard Worker   if (!file.Open(path))
45*f6dc9357SAndroid Build Coastguard Worker     return false;
46*f6dc9357SAndroid Build Coastguard Worker   if (!file.GetFileInformation(&Info))
47*f6dc9357SAndroid Build Coastguard Worker     return false;
48*f6dc9357SAndroid Build Coastguard Worker 
49*f6dc9357SAndroid Build Coastguard Worker   const UInt64 size = GetSize();
50*f6dc9357SAndroid Build Coastguard Worker   const size_t size2 = (size_t)size;
51*f6dc9357SAndroid Build Coastguard Worker   if (size2 != size || size2 > (1 << 28))
52*f6dc9357SAndroid Build Coastguard Worker   {
53*f6dc9357SAndroid Build Coastguard Worker     SetLastError(1);
54*f6dc9357SAndroid Build Coastguard Worker     return false;
55*f6dc9357SAndroid Build Coastguard Worker   }
56*f6dc9357SAndroid Build Coastguard Worker 
57*f6dc9357SAndroid Build Coastguard Worker   Data.Alloc(size2);
58*f6dc9357SAndroid Build Coastguard Worker 
59*f6dc9357SAndroid Build Coastguard Worker   size_t processedSize;
60*f6dc9357SAndroid Build Coastguard Worker   if (!file.ReadFull(Data, size2, processedSize))
61*f6dc9357SAndroid Build Coastguard Worker     return false;
62*f6dc9357SAndroid Build Coastguard Worker   if (processedSize != size2)
63*f6dc9357SAndroid Build Coastguard Worker   {
64*f6dc9357SAndroid Build Coastguard Worker     SetLastError(1);
65*f6dc9357SAndroid Build Coastguard Worker     return false;
66*f6dc9357SAndroid Build Coastguard Worker   }
67*f6dc9357SAndroid Build Coastguard Worker   IsOpen = true;
68*f6dc9357SAndroid Build Coastguard Worker   return true;
69*f6dc9357SAndroid Build Coastguard Worker }
70*f6dc9357SAndroid Build Coastguard Worker 
71*f6dc9357SAndroid Build Coastguard Worker 
CreateComplexDir_for_File(const FString & path)72*f6dc9357SAndroid Build Coastguard Worker static bool CreateComplexDir_for_File(const FString &path)
73*f6dc9357SAndroid Build Coastguard Worker {
74*f6dc9357SAndroid Build Coastguard Worker   FString resDirPrefix;
75*f6dc9357SAndroid Build Coastguard Worker   FString resFileName;
76*f6dc9357SAndroid Build Coastguard Worker   if (!GetFullPathAndSplit(path, resDirPrefix, resFileName))
77*f6dc9357SAndroid Build Coastguard Worker     return false;
78*f6dc9357SAndroid Build Coastguard Worker   return CreateComplexDir(resDirPrefix);
79*f6dc9357SAndroid Build Coastguard Worker }
80*f6dc9357SAndroid Build Coastguard Worker 
81*f6dc9357SAndroid Build Coastguard Worker 
ParseNumberString(const FString & s,UInt32 & number)82*f6dc9357SAndroid Build Coastguard Worker static bool ParseNumberString(const FString &s, UInt32 &number)
83*f6dc9357SAndroid Build Coastguard Worker {
84*f6dc9357SAndroid Build Coastguard Worker   const FChar *end;
85*f6dc9357SAndroid Build Coastguard Worker   UInt64 result = ConvertStringToUInt64(s, &end);
86*f6dc9357SAndroid Build Coastguard Worker   if (*end != 0 || s.IsEmpty() || result > (UInt32)0x7FFFFFFF)
87*f6dc9357SAndroid Build Coastguard Worker     return false;
88*f6dc9357SAndroid Build Coastguard Worker   number = (UInt32)result;
89*f6dc9357SAndroid Build Coastguard Worker   return true;
90*f6dc9357SAndroid Build Coastguard Worker }
91*f6dc9357SAndroid Build Coastguard Worker 
92*f6dc9357SAndroid Build Coastguard Worker 
WriteFile(const FString & path,bool createAlways,const CFileDataInfo & fdi,const CPanel & panel)93*f6dc9357SAndroid Build Coastguard Worker static void WriteFile(const FString &path, bool createAlways, const CFileDataInfo &fdi, const CPanel &panel)
94*f6dc9357SAndroid Build Coastguard Worker {
95*f6dc9357SAndroid Build Coastguard Worker   NIO::COutFile outFile;
96*f6dc9357SAndroid Build Coastguard Worker   if (!outFile.Create_ALWAYS_or_NEW(path, createAlways)) // (createAlways = false) means CREATE_NEW
97*f6dc9357SAndroid Build Coastguard Worker   {
98*f6dc9357SAndroid Build Coastguard Worker     panel.MessageBox_LastError();
99*f6dc9357SAndroid Build Coastguard Worker     return;
100*f6dc9357SAndroid Build Coastguard Worker   }
101*f6dc9357SAndroid Build Coastguard Worker   UInt32 processedSize;
102*f6dc9357SAndroid Build Coastguard Worker   if (!outFile.Write(fdi.Data, (UInt32)fdi.Data.Size(), processedSize))
103*f6dc9357SAndroid Build Coastguard Worker   {
104*f6dc9357SAndroid Build Coastguard Worker     panel.MessageBox_LastError();
105*f6dc9357SAndroid Build Coastguard Worker     return;
106*f6dc9357SAndroid Build Coastguard Worker   }
107*f6dc9357SAndroid Build Coastguard Worker   if (processedSize != fdi.Data.Size())
108*f6dc9357SAndroid Build Coastguard Worker   {
109*f6dc9357SAndroid Build Coastguard Worker     panel.MessageBox_Error(L"Write error");
110*f6dc9357SAndroid Build Coastguard Worker     return;
111*f6dc9357SAndroid Build Coastguard Worker   }
112*f6dc9357SAndroid Build Coastguard Worker   if (!outFile.SetTime(
113*f6dc9357SAndroid Build Coastguard Worker       &fdi.Info.ftCreationTime,
114*f6dc9357SAndroid Build Coastguard Worker       &fdi.Info.ftLastAccessTime,
115*f6dc9357SAndroid Build Coastguard Worker       &fdi.Info.ftLastWriteTime))
116*f6dc9357SAndroid Build Coastguard Worker   {
117*f6dc9357SAndroid Build Coastguard Worker     panel.MessageBox_LastError();
118*f6dc9357SAndroid Build Coastguard Worker     return;
119*f6dc9357SAndroid Build Coastguard Worker   }
120*f6dc9357SAndroid Build Coastguard Worker 
121*f6dc9357SAndroid Build Coastguard Worker   if (!SetFileAttrib(path, fdi.Info.dwFileAttributes))
122*f6dc9357SAndroid Build Coastguard Worker   {
123*f6dc9357SAndroid Build Coastguard Worker     panel.MessageBox_LastError();
124*f6dc9357SAndroid Build Coastguard Worker     return;
125*f6dc9357SAndroid Build Coastguard Worker   }
126*f6dc9357SAndroid Build Coastguard Worker }
127*f6dc9357SAndroid Build Coastguard Worker 
128*f6dc9357SAndroid Build Coastguard Worker 
FILETIME_to_UInt64(const FILETIME & ft)129*f6dc9357SAndroid Build Coastguard Worker static UInt64 FILETIME_to_UInt64(const FILETIME &ft)
130*f6dc9357SAndroid Build Coastguard Worker {
131*f6dc9357SAndroid Build Coastguard Worker   return ft.dwLowDateTime | ((UInt64)ft.dwHighDateTime << 32);
132*f6dc9357SAndroid Build Coastguard Worker }
133*f6dc9357SAndroid Build Coastguard Worker 
UInt64_TO_FILETIME(UInt64 v,FILETIME & ft)134*f6dc9357SAndroid Build Coastguard Worker static void UInt64_TO_FILETIME(UInt64 v, FILETIME &ft)
135*f6dc9357SAndroid Build Coastguard Worker {
136*f6dc9357SAndroid Build Coastguard Worker   ft.dwLowDateTime = (DWORD)v;
137*f6dc9357SAndroid Build Coastguard Worker   ft.dwHighDateTime = (DWORD)(v >> 32);
138*f6dc9357SAndroid Build Coastguard Worker }
139*f6dc9357SAndroid Build Coastguard Worker 
140*f6dc9357SAndroid Build Coastguard Worker 
VerCtrl(unsigned id)141*f6dc9357SAndroid Build Coastguard Worker void CApp::VerCtrl(unsigned id)
142*f6dc9357SAndroid Build Coastguard Worker {
143*f6dc9357SAndroid Build Coastguard Worker   const CPanel &panel = GetFocusedPanel();
144*f6dc9357SAndroid Build Coastguard Worker 
145*f6dc9357SAndroid Build Coastguard Worker   if (!panel.Is_IO_FS_Folder())
146*f6dc9357SAndroid Build Coastguard Worker   {
147*f6dc9357SAndroid Build Coastguard Worker     panel.MessageBox_Error_UnsupportOperation();
148*f6dc9357SAndroid Build Coastguard Worker     return;
149*f6dc9357SAndroid Build Coastguard Worker   }
150*f6dc9357SAndroid Build Coastguard Worker 
151*f6dc9357SAndroid Build Coastguard Worker   CRecordVector<UInt32> indices;
152*f6dc9357SAndroid Build Coastguard Worker   panel.Get_ItemIndices_Selected(indices);
153*f6dc9357SAndroid Build Coastguard Worker 
154*f6dc9357SAndroid Build Coastguard Worker   if (indices.Size() != 1)
155*f6dc9357SAndroid Build Coastguard Worker   {
156*f6dc9357SAndroid Build Coastguard Worker     // panel.MessageBox_Error_UnsupportOperation();
157*f6dc9357SAndroid Build Coastguard Worker     return;
158*f6dc9357SAndroid Build Coastguard Worker   }
159*f6dc9357SAndroid Build Coastguard Worker 
160*f6dc9357SAndroid Build Coastguard Worker   const FString path = us2fs(panel.GetItemFullPath(indices[0]));
161*f6dc9357SAndroid Build Coastguard Worker 
162*f6dc9357SAndroid Build Coastguard Worker   UString vercPath;
163*f6dc9357SAndroid Build Coastguard Worker   ReadReg_VerCtrlPath(vercPath);
164*f6dc9357SAndroid Build Coastguard Worker   if (vercPath.IsEmpty())
165*f6dc9357SAndroid Build Coastguard Worker     return;
166*f6dc9357SAndroid Build Coastguard Worker   NName::NormalizeDirPathPrefix(vercPath);
167*f6dc9357SAndroid Build Coastguard Worker 
168*f6dc9357SAndroid Build Coastguard Worker   FString dirPrefix;
169*f6dc9357SAndroid Build Coastguard Worker   FString fileName;
170*f6dc9357SAndroid Build Coastguard Worker   if (!GetFullPathAndSplit(path, dirPrefix, fileName))
171*f6dc9357SAndroid Build Coastguard Worker   {
172*f6dc9357SAndroid Build Coastguard Worker     panel.MessageBox_LastError();
173*f6dc9357SAndroid Build Coastguard Worker     return;
174*f6dc9357SAndroid Build Coastguard Worker   }
175*f6dc9357SAndroid Build Coastguard Worker 
176*f6dc9357SAndroid Build Coastguard Worker   const FString dirPrefix2 = us2fs(vercPath) + ConvertPath_to_Ctrl(dirPrefix);
177*f6dc9357SAndroid Build Coastguard Worker   const FString path2 = dirPrefix2 + fileName;
178*f6dc9357SAndroid Build Coastguard Worker 
179*f6dc9357SAndroid Build Coastguard Worker   bool sameTime = false;
180*f6dc9357SAndroid Build Coastguard Worker   bool sameData = false;
181*f6dc9357SAndroid Build Coastguard Worker   bool areIdentical = false;
182*f6dc9357SAndroid Build Coastguard Worker 
183*f6dc9357SAndroid Build Coastguard Worker   CFileDataInfo fdi, fdi2;
184*f6dc9357SAndroid Build Coastguard Worker   if (!fdi.Read(path))
185*f6dc9357SAndroid Build Coastguard Worker   {
186*f6dc9357SAndroid Build Coastguard Worker     panel.MessageBox_LastError();
187*f6dc9357SAndroid Build Coastguard Worker     return;
188*f6dc9357SAndroid Build Coastguard Worker   }
189*f6dc9357SAndroid Build Coastguard Worker 
190*f6dc9357SAndroid Build Coastguard Worker   if (fdi2.Read(path2))
191*f6dc9357SAndroid Build Coastguard Worker   {
192*f6dc9357SAndroid Build Coastguard Worker     sameData = (fdi.Data == fdi2.Data);
193*f6dc9357SAndroid Build Coastguard Worker     sameTime = (CompareFileTime(&fdi.Info.ftLastWriteTime, &fdi2.Info.ftLastWriteTime) == 0);
194*f6dc9357SAndroid Build Coastguard Worker     areIdentical = (sameData && sameTime);
195*f6dc9357SAndroid Build Coastguard Worker   }
196*f6dc9357SAndroid Build Coastguard Worker 
197*f6dc9357SAndroid Build Coastguard Worker   const bool isReadOnly = NAttributes::IsReadOnly(fdi.Info.dwFileAttributes);
198*f6dc9357SAndroid Build Coastguard Worker 
199*f6dc9357SAndroid Build Coastguard Worker   if (id == IDM_VER_EDIT)
200*f6dc9357SAndroid Build Coastguard Worker   {
201*f6dc9357SAndroid Build Coastguard Worker     if (!isReadOnly)
202*f6dc9357SAndroid Build Coastguard Worker     {
203*f6dc9357SAndroid Build Coastguard Worker       panel.MessageBox_Error(L"File is not read-only");
204*f6dc9357SAndroid Build Coastguard Worker       return;
205*f6dc9357SAndroid Build Coastguard Worker     }
206*f6dc9357SAndroid Build Coastguard Worker 
207*f6dc9357SAndroid Build Coastguard Worker     if (!areIdentical)
208*f6dc9357SAndroid Build Coastguard Worker     {
209*f6dc9357SAndroid Build Coastguard Worker       if (fdi2.IsOpen)
210*f6dc9357SAndroid Build Coastguard Worker       {
211*f6dc9357SAndroid Build Coastguard Worker         NFind::CEnumerator enumerator;
212*f6dc9357SAndroid Build Coastguard Worker         FString d2 = dirPrefix2;
213*f6dc9357SAndroid Build Coastguard Worker         d2 += "_7vc";
214*f6dc9357SAndroid Build Coastguard Worker         d2.Add_PathSepar();
215*f6dc9357SAndroid Build Coastguard Worker         d2 += fileName;
216*f6dc9357SAndroid Build Coastguard Worker         d2.Add_PathSepar();
217*f6dc9357SAndroid Build Coastguard Worker         enumerator.SetDirPrefix(d2);
218*f6dc9357SAndroid Build Coastguard Worker         NFind::CDirEntry fi;
219*f6dc9357SAndroid Build Coastguard Worker         Int32 maxVal = -1;
220*f6dc9357SAndroid Build Coastguard Worker         while (enumerator.Next(fi))
221*f6dc9357SAndroid Build Coastguard Worker         {
222*f6dc9357SAndroid Build Coastguard Worker           UInt32 val;
223*f6dc9357SAndroid Build Coastguard Worker           if (!ParseNumberString(fi.Name, val))
224*f6dc9357SAndroid Build Coastguard Worker             continue;
225*f6dc9357SAndroid Build Coastguard Worker           if ((Int32)val > maxVal)
226*f6dc9357SAndroid Build Coastguard Worker             maxVal = (Int32)val;
227*f6dc9357SAndroid Build Coastguard Worker         }
228*f6dc9357SAndroid Build Coastguard Worker 
229*f6dc9357SAndroid Build Coastguard Worker         UInt32 next = (UInt32)maxVal + 1;
230*f6dc9357SAndroid Build Coastguard Worker         if (maxVal < 0)
231*f6dc9357SAndroid Build Coastguard Worker         {
232*f6dc9357SAndroid Build Coastguard Worker           next = 1;
233*f6dc9357SAndroid Build Coastguard Worker           if (!::CreateComplexDir_for_File(path2))
234*f6dc9357SAndroid Build Coastguard Worker           {
235*f6dc9357SAndroid Build Coastguard Worker             panel.MessageBox_LastError();
236*f6dc9357SAndroid Build Coastguard Worker             return;
237*f6dc9357SAndroid Build Coastguard Worker           }
238*f6dc9357SAndroid Build Coastguard Worker         }
239*f6dc9357SAndroid Build Coastguard Worker 
240*f6dc9357SAndroid Build Coastguard Worker         // we rename old file2 to some name;
241*f6dc9357SAndroid Build Coastguard Worker         FString path_num = d2;
242*f6dc9357SAndroid Build Coastguard Worker         {
243*f6dc9357SAndroid Build Coastguard Worker           AString t;
244*f6dc9357SAndroid Build Coastguard Worker           t.Add_UInt32((UInt32)next);
245*f6dc9357SAndroid Build Coastguard Worker           while (t.Len() < 3)
246*f6dc9357SAndroid Build Coastguard Worker             t.InsertAtFront('0');
247*f6dc9357SAndroid Build Coastguard Worker           path_num += t;
248*f6dc9357SAndroid Build Coastguard Worker         }
249*f6dc9357SAndroid Build Coastguard Worker 
250*f6dc9357SAndroid Build Coastguard Worker         if (maxVal < 0)
251*f6dc9357SAndroid Build Coastguard Worker         {
252*f6dc9357SAndroid Build Coastguard Worker           if (!::CreateComplexDir_for_File(path_num))
253*f6dc9357SAndroid Build Coastguard Worker           {
254*f6dc9357SAndroid Build Coastguard Worker             panel.MessageBox_LastError();
255*f6dc9357SAndroid Build Coastguard Worker             return;
256*f6dc9357SAndroid Build Coastguard Worker           }
257*f6dc9357SAndroid Build Coastguard Worker         }
258*f6dc9357SAndroid Build Coastguard Worker 
259*f6dc9357SAndroid Build Coastguard Worker         if (!NDir::MyMoveFile(path2, path_num))
260*f6dc9357SAndroid Build Coastguard Worker         {
261*f6dc9357SAndroid Build Coastguard Worker           panel.MessageBox_LastError();
262*f6dc9357SAndroid Build Coastguard Worker           return;
263*f6dc9357SAndroid Build Coastguard Worker         }
264*f6dc9357SAndroid Build Coastguard Worker       }
265*f6dc9357SAndroid Build Coastguard Worker       else
266*f6dc9357SAndroid Build Coastguard Worker       {
267*f6dc9357SAndroid Build Coastguard Worker         if (!::CreateComplexDir_for_File(path2))
268*f6dc9357SAndroid Build Coastguard Worker         {
269*f6dc9357SAndroid Build Coastguard Worker           panel.MessageBox_LastError();
270*f6dc9357SAndroid Build Coastguard Worker           return;
271*f6dc9357SAndroid Build Coastguard Worker         }
272*f6dc9357SAndroid Build Coastguard Worker       }
273*f6dc9357SAndroid Build Coastguard Worker       /*
274*f6dc9357SAndroid Build Coastguard Worker       if (!::CopyFile(fs2fas(path), fs2fas(path2), TRUE))
275*f6dc9357SAndroid Build Coastguard Worker       {
276*f6dc9357SAndroid Build Coastguard Worker         panel.MessageBox_LastError();
277*f6dc9357SAndroid Build Coastguard Worker         return;
278*f6dc9357SAndroid Build Coastguard Worker       }
279*f6dc9357SAndroid Build Coastguard Worker       */
280*f6dc9357SAndroid Build Coastguard Worker       WriteFile(path2,
281*f6dc9357SAndroid Build Coastguard Worker           false,  // (createAlways = false) means CREATE_NEW
282*f6dc9357SAndroid Build Coastguard Worker           fdi, panel);
283*f6dc9357SAndroid Build Coastguard Worker     }
284*f6dc9357SAndroid Build Coastguard Worker 
285*f6dc9357SAndroid Build Coastguard Worker     if (!SetFileAttrib(path, fdi.Info.dwFileAttributes & ~(DWORD)FILE_ATTRIBUTE_READONLY))
286*f6dc9357SAndroid Build Coastguard Worker     {
287*f6dc9357SAndroid Build Coastguard Worker       panel.MessageBox_LastError();
288*f6dc9357SAndroid Build Coastguard Worker       return;
289*f6dc9357SAndroid Build Coastguard Worker     }
290*f6dc9357SAndroid Build Coastguard Worker 
291*f6dc9357SAndroid Build Coastguard Worker     return;
292*f6dc9357SAndroid Build Coastguard Worker   }
293*f6dc9357SAndroid Build Coastguard Worker 
294*f6dc9357SAndroid Build Coastguard Worker   if (isReadOnly)
295*f6dc9357SAndroid Build Coastguard Worker   {
296*f6dc9357SAndroid Build Coastguard Worker     panel.MessageBox_Error(L"File is read-only");
297*f6dc9357SAndroid Build Coastguard Worker     return;
298*f6dc9357SAndroid Build Coastguard Worker   }
299*f6dc9357SAndroid Build Coastguard Worker 
300*f6dc9357SAndroid Build Coastguard Worker   if (id == IDM_VER_COMMIT)
301*f6dc9357SAndroid Build Coastguard Worker   {
302*f6dc9357SAndroid Build Coastguard Worker     if (sameData)
303*f6dc9357SAndroid Build Coastguard Worker     {
304*f6dc9357SAndroid Build Coastguard Worker       if (!sameTime)
305*f6dc9357SAndroid Build Coastguard Worker       {
306*f6dc9357SAndroid Build Coastguard Worker         panel.MessageBox_Error(
307*f6dc9357SAndroid Build Coastguard Worker           L"Same data, but different timestamps.\n"
308*f6dc9357SAndroid Build Coastguard Worker           L"Use `Revert` to recover timestamp.");
309*f6dc9357SAndroid Build Coastguard Worker         return;
310*f6dc9357SAndroid Build Coastguard Worker       }
311*f6dc9357SAndroid Build Coastguard Worker     }
312*f6dc9357SAndroid Build Coastguard Worker 
313*f6dc9357SAndroid Build Coastguard Worker     const UInt64 timeStampOriginal = FILETIME_to_UInt64(fdi.Info.ftLastWriteTime);
314*f6dc9357SAndroid Build Coastguard Worker     UInt64 timeStamp2 = 0;
315*f6dc9357SAndroid Build Coastguard Worker     if (fdi2.IsOpen)
316*f6dc9357SAndroid Build Coastguard Worker       timeStamp2 = FILETIME_to_UInt64(fdi2.Info.ftLastWriteTime);
317*f6dc9357SAndroid Build Coastguard Worker 
318*f6dc9357SAndroid Build Coastguard Worker     if (timeStampOriginal > timeStamp2)
319*f6dc9357SAndroid Build Coastguard Worker     {
320*f6dc9357SAndroid Build Coastguard Worker       const UInt64 k_Ntfs_prec = 10000000;
321*f6dc9357SAndroid Build Coastguard Worker       UInt64 timeStamp = timeStampOriginal;
322*f6dc9357SAndroid Build Coastguard Worker       const UInt32 k_precs[] = { 60 * 60, 60, 2, 1 };
323*f6dc9357SAndroid Build Coastguard Worker       for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_precs); i++)
324*f6dc9357SAndroid Build Coastguard Worker       {
325*f6dc9357SAndroid Build Coastguard Worker         timeStamp = timeStampOriginal;
326*f6dc9357SAndroid Build Coastguard Worker         const UInt64 prec = k_Ntfs_prec * k_precs[i];
327*f6dc9357SAndroid Build Coastguard Worker         // timeStamp += prec - 1; // for rounding up
328*f6dc9357SAndroid Build Coastguard Worker         timeStamp /= prec;
329*f6dc9357SAndroid Build Coastguard Worker         timeStamp *= prec;
330*f6dc9357SAndroid Build Coastguard Worker         if (timeStamp > timeStamp2)
331*f6dc9357SAndroid Build Coastguard Worker           break;
332*f6dc9357SAndroid Build Coastguard Worker       }
333*f6dc9357SAndroid Build Coastguard Worker 
334*f6dc9357SAndroid Build Coastguard Worker       if (timeStamp != timeStampOriginal
335*f6dc9357SAndroid Build Coastguard Worker           && timeStamp > timeStamp2)
336*f6dc9357SAndroid Build Coastguard Worker       {
337*f6dc9357SAndroid Build Coastguard Worker         FILETIME mTime;
338*f6dc9357SAndroid Build Coastguard Worker         UInt64_TO_FILETIME(timeStamp, mTime);
339*f6dc9357SAndroid Build Coastguard Worker         // NDir::SetFileAttrib(path, 0);
340*f6dc9357SAndroid Build Coastguard Worker         {
341*f6dc9357SAndroid Build Coastguard Worker           NIO::COutFile outFile;
342*f6dc9357SAndroid Build Coastguard Worker           if (!outFile.Open_EXISTING(path))
343*f6dc9357SAndroid Build Coastguard Worker           {
344*f6dc9357SAndroid Build Coastguard Worker             panel.MessageBox_LastError();
345*f6dc9357SAndroid Build Coastguard Worker             return;
346*f6dc9357SAndroid Build Coastguard Worker             // if (::GetLastError() != ERROR_SUCCESS)
347*f6dc9357SAndroid Build Coastguard Worker             // throw "open error";
348*f6dc9357SAndroid Build Coastguard Worker           }
349*f6dc9357SAndroid Build Coastguard Worker           else
350*f6dc9357SAndroid Build Coastguard Worker           {
351*f6dc9357SAndroid Build Coastguard Worker             const UInt64 cTime = FILETIME_to_UInt64(fdi.Info.ftCreationTime);
352*f6dc9357SAndroid Build Coastguard Worker             if (cTime > timeStamp)
353*f6dc9357SAndroid Build Coastguard Worker               outFile.SetTime(&mTime, NULL, &mTime);
354*f6dc9357SAndroid Build Coastguard Worker             else
355*f6dc9357SAndroid Build Coastguard Worker               outFile.SetMTime(&mTime);
356*f6dc9357SAndroid Build Coastguard Worker           }
357*f6dc9357SAndroid Build Coastguard Worker         }
358*f6dc9357SAndroid Build Coastguard Worker       }
359*f6dc9357SAndroid Build Coastguard Worker     }
360*f6dc9357SAndroid Build Coastguard Worker 
361*f6dc9357SAndroid Build Coastguard Worker     if (!SetFileAttrib(path, fdi.Info.dwFileAttributes | FILE_ATTRIBUTE_READONLY))
362*f6dc9357SAndroid Build Coastguard Worker     {
363*f6dc9357SAndroid Build Coastguard Worker       panel.MessageBox_LastError();
364*f6dc9357SAndroid Build Coastguard Worker       return;
365*f6dc9357SAndroid Build Coastguard Worker     }
366*f6dc9357SAndroid Build Coastguard Worker     return;
367*f6dc9357SAndroid Build Coastguard Worker   }
368*f6dc9357SAndroid Build Coastguard Worker 
369*f6dc9357SAndroid Build Coastguard Worker   if (id == IDM_VER_REVERT)
370*f6dc9357SAndroid Build Coastguard Worker   {
371*f6dc9357SAndroid Build Coastguard Worker     if (!fdi2.IsOpen)
372*f6dc9357SAndroid Build Coastguard Worker     {
373*f6dc9357SAndroid Build Coastguard Worker       panel.MessageBox_Error(L"No file to revert");
374*f6dc9357SAndroid Build Coastguard Worker       return;
375*f6dc9357SAndroid Build Coastguard Worker     }
376*f6dc9357SAndroid Build Coastguard Worker     if (!sameData || !sameTime)
377*f6dc9357SAndroid Build Coastguard Worker     {
378*f6dc9357SAndroid Build Coastguard Worker       if (!sameData)
379*f6dc9357SAndroid Build Coastguard Worker       {
380*f6dc9357SAndroid Build Coastguard Worker         /*
381*f6dc9357SAndroid Build Coastguard Worker         UString m;
382*f6dc9357SAndroid Build Coastguard Worker         m = "Are you sure you want to revert file ?";
383*f6dc9357SAndroid Build Coastguard Worker         m.Add_LF();
384*f6dc9357SAndroid Build Coastguard Worker         m += path;
385*f6dc9357SAndroid Build Coastguard Worker         if (::MessageBoxW(panel.GetParent(), m, L"Version Control: File Revert", MB_OKCANCEL | MB_ICONQUESTION) != IDOK)
386*f6dc9357SAndroid Build Coastguard Worker           return;
387*f6dc9357SAndroid Build Coastguard Worker         */
388*f6dc9357SAndroid Build Coastguard Worker         COverwriteDialog dialog;
389*f6dc9357SAndroid Build Coastguard Worker 
390*f6dc9357SAndroid Build Coastguard Worker         dialog.OldFileInfo.SetTime(fdi.Info.ftLastWriteTime);
391*f6dc9357SAndroid Build Coastguard Worker         dialog.OldFileInfo.SetSize(fdi.GetSize());
392*f6dc9357SAndroid Build Coastguard Worker         dialog.OldFileInfo.Path = fs2us(path);
393*f6dc9357SAndroid Build Coastguard Worker 
394*f6dc9357SAndroid Build Coastguard Worker         dialog.NewFileInfo.SetTime(fdi2.Info.ftLastWriteTime);
395*f6dc9357SAndroid Build Coastguard Worker         dialog.NewFileInfo.SetSize(fdi2.GetSize());
396*f6dc9357SAndroid Build Coastguard Worker         dialog.NewFileInfo.Path = fs2us(path2);
397*f6dc9357SAndroid Build Coastguard Worker 
398*f6dc9357SAndroid Build Coastguard Worker         dialog.ShowExtraButtons = false;
399*f6dc9357SAndroid Build Coastguard Worker         dialog.DefaultButton_is_NO = true;
400*f6dc9357SAndroid Build Coastguard Worker 
401*f6dc9357SAndroid Build Coastguard Worker         INT_PTR writeAnswer = dialog.Create(panel.GetParent());
402*f6dc9357SAndroid Build Coastguard Worker 
403*f6dc9357SAndroid Build Coastguard Worker         if (writeAnswer != IDYES)
404*f6dc9357SAndroid Build Coastguard Worker           return;
405*f6dc9357SAndroid Build Coastguard Worker       }
406*f6dc9357SAndroid Build Coastguard Worker 
407*f6dc9357SAndroid Build Coastguard Worker       WriteFile(path,
408*f6dc9357SAndroid Build Coastguard Worker           true,  // (createAlways = true) means CREATE_ALWAYS
409*f6dc9357SAndroid Build Coastguard Worker           fdi2, panel);
410*f6dc9357SAndroid Build Coastguard Worker     }
411*f6dc9357SAndroid Build Coastguard Worker     else
412*f6dc9357SAndroid Build Coastguard Worker     {
413*f6dc9357SAndroid Build Coastguard Worker       if (!SetFileAttrib(path, fdi2.Info.dwFileAttributes | FILE_ATTRIBUTE_READONLY))
414*f6dc9357SAndroid Build Coastguard Worker       {
415*f6dc9357SAndroid Build Coastguard Worker         panel.MessageBox_LastError();
416*f6dc9357SAndroid Build Coastguard Worker         return;
417*f6dc9357SAndroid Build Coastguard Worker       }
418*f6dc9357SAndroid Build Coastguard Worker     }
419*f6dc9357SAndroid Build Coastguard Worker     return;
420*f6dc9357SAndroid Build Coastguard Worker   }
421*f6dc9357SAndroid Build Coastguard Worker 
422*f6dc9357SAndroid Build Coastguard Worker   // if (id == IDM_VER_DIFF)
423*f6dc9357SAndroid Build Coastguard Worker   {
424*f6dc9357SAndroid Build Coastguard Worker     if (!fdi2.IsOpen)
425*f6dc9357SAndroid Build Coastguard Worker       return;
426*f6dc9357SAndroid Build Coastguard Worker     DiffFiles(fs2us(path2), fs2us(path));
427*f6dc9357SAndroid Build Coastguard Worker   }
428*f6dc9357SAndroid Build Coastguard Worker }
429