mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-06 13:14:59 -06:00
343 lines
7.9 KiB
C++
343 lines
7.9 KiB
C++
// LinkDialog.cpp
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#include "../../../Windows/ErrorMsg.h"
|
|
#include "../../../Windows/FileDir.h"
|
|
#include "../../../Windows/FileFind.h"
|
|
#include "../../../Windows/FileIO.h"
|
|
#include "../../../Windows/FileName.h"
|
|
|
|
#ifdef LANG
|
|
#include "LangUtils.h"
|
|
#endif
|
|
|
|
#include "BrowseDialog.h"
|
|
#include "CopyDialogRes.h"
|
|
#include "LinkDialog.h"
|
|
#include "resourceGui.h"
|
|
|
|
#include "App.h"
|
|
|
|
#include "resource.h"
|
|
|
|
extern bool g_SymLink_Supported;
|
|
|
|
using namespace NWindows;
|
|
using namespace NFile;
|
|
|
|
#ifdef LANG
|
|
static const UInt32 kLangIDs[] =
|
|
{
|
|
IDB_LINK_LINK,
|
|
IDT_LINK_PATH_FROM,
|
|
IDT_LINK_PATH_TO,
|
|
IDG_LINK_TYPE,
|
|
IDR_LINK_TYPE_HARD,
|
|
IDR_LINK_TYPE_SYM_FILE,
|
|
IDR_LINK_TYPE_SYM_DIR,
|
|
IDR_LINK_TYPE_JUNCTION
|
|
};
|
|
#endif
|
|
|
|
static bool GetSymLink(CFSTR path, CReparseAttr &attr)
|
|
{
|
|
NFile::NIO::CInFile file;
|
|
if (!file.Open(path,
|
|
FILE_SHARE_READ,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS))
|
|
return false;
|
|
|
|
const unsigned kBufSize = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
|
|
CByteArr buf(kBufSize);
|
|
DWORD returnedSize;
|
|
if (!file.DeviceIoControlOut(my_FSCTL_GET_REPARSE_POINT, buf, kBufSize, &returnedSize))
|
|
return false;
|
|
|
|
if (!attr.Parse(buf, returnedSize))
|
|
return false;
|
|
|
|
CByteBuffer data2;
|
|
if (!FillLinkData(data2, attr.GetPath(), attr.IsSymLink()))
|
|
return false;
|
|
|
|
if (data2.Size() != returnedSize ||
|
|
memcmp(data2, buf, returnedSize) != 0)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static const int k_LinkType_Buttons[] =
|
|
{
|
|
IDR_LINK_TYPE_HARD,
|
|
IDR_LINK_TYPE_SYM_FILE,
|
|
IDR_LINK_TYPE_SYM_DIR,
|
|
IDR_LINK_TYPE_JUNCTION
|
|
};
|
|
|
|
void CLinkDialog::Set_LinkType_Radio(int idb)
|
|
{
|
|
CheckRadioButton(k_LinkType_Buttons[0], k_LinkType_Buttons[ARRAY_SIZE(k_LinkType_Buttons) - 1], idb);
|
|
}
|
|
|
|
bool CLinkDialog::OnInit()
|
|
{
|
|
#ifdef LANG
|
|
LangSetWindowText(*this, IDD_LINK);
|
|
LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs));
|
|
#endif
|
|
_pathFromCombo.Attach(GetItem(IDC_LINK_PATH_FROM));
|
|
_pathToCombo.Attach(GetItem(IDC_LINK_PATH_TO));
|
|
|
|
if (!FilePath.IsEmpty())
|
|
{
|
|
NFile::NFind::CFileInfo fi;
|
|
int linkType = 0;
|
|
if (!fi.Find(us2fs(FilePath)))
|
|
linkType = IDR_LINK_TYPE_SYM_FILE;
|
|
else
|
|
{
|
|
if (fi.HasReparsePoint())
|
|
{
|
|
CReparseAttr attr;
|
|
bool res = GetSymLink(us2fs(FilePath), attr);
|
|
|
|
UString s = attr.PrintName;
|
|
if (!attr.IsOkNamePair())
|
|
{
|
|
s += L" : ";
|
|
s += attr.SubsName;
|
|
}
|
|
if (!res)
|
|
s = L"ERROR: " + s;
|
|
|
|
SetItemText(IDT_LINK_PATH_TO_CUR, s);
|
|
|
|
UString destPath = attr.GetPath();
|
|
_pathFromCombo.SetText(FilePath);
|
|
_pathToCombo.SetText(destPath);
|
|
|
|
if (res)
|
|
{
|
|
if (attr.IsMountPoint())
|
|
linkType = IDR_LINK_TYPE_JUNCTION;
|
|
if (attr.IsSymLink())
|
|
{
|
|
linkType =
|
|
fi.IsDir() ?
|
|
IDR_LINK_TYPE_SYM_DIR :
|
|
IDR_LINK_TYPE_SYM_FILE;
|
|
// if (attr.IsRelative()) linkType = IDR_LINK_TYPE_SYM_RELATIVE;
|
|
}
|
|
|
|
if (linkType != 0)
|
|
Set_LinkType_Radio(linkType);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_pathFromCombo.SetText(AnotherPath);
|
|
_pathToCombo.SetText(FilePath);
|
|
if (fi.IsDir())
|
|
linkType = g_SymLink_Supported ?
|
|
IDR_LINK_TYPE_SYM_DIR :
|
|
IDR_LINK_TYPE_JUNCTION;
|
|
else
|
|
linkType = IDR_LINK_TYPE_HARD;
|
|
}
|
|
}
|
|
if (linkType != 0)
|
|
Set_LinkType_Radio(linkType);
|
|
}
|
|
|
|
NormalizeSize();
|
|
return CModalDialog::OnInit();
|
|
}
|
|
|
|
bool CLinkDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize)
|
|
{
|
|
int mx, my;
|
|
GetMargins(8, mx, my);
|
|
int bx1, bx2, by;
|
|
GetItemSizes(IDCANCEL, bx1, by);
|
|
GetItemSizes(IDB_LINK_LINK, bx2, by);
|
|
int yPos = ySize - my - by;
|
|
int xPos = xSize - mx - bx1;
|
|
|
|
InvalidateRect(NULL);
|
|
|
|
{
|
|
RECT r, r2;
|
|
GetClientRectOfItem(IDB_LINK_PATH_FROM, r);
|
|
GetClientRectOfItem(IDB_LINK_PATH_TO, r2);
|
|
int bx = RECT_SIZE_X(r);
|
|
int newButtonXpos = xSize - mx - bx;
|
|
|
|
MoveItem(IDB_LINK_PATH_FROM, newButtonXpos, r.top, bx, RECT_SIZE_Y(r));
|
|
MoveItem(IDB_LINK_PATH_TO, newButtonXpos, r2.top, bx, RECT_SIZE_Y(r2));
|
|
|
|
int newComboXsize = newButtonXpos - mx - mx;
|
|
ChangeSubWindowSizeX(_pathFromCombo, newComboXsize);
|
|
ChangeSubWindowSizeX(_pathToCombo, newComboXsize);
|
|
}
|
|
|
|
MoveItem(IDCANCEL, xPos, yPos, bx1, by);
|
|
MoveItem(IDB_LINK_LINK, xPos - mx - bx2, yPos, bx2, by);
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CLinkDialog::OnButtonClicked(int buttonID, HWND buttonHWND)
|
|
{
|
|
switch (buttonID)
|
|
{
|
|
case IDB_LINK_PATH_FROM:
|
|
OnButton_SetPath(false);
|
|
return true;
|
|
case IDB_LINK_PATH_TO:
|
|
OnButton_SetPath(true);
|
|
return true;
|
|
case IDB_LINK_LINK:
|
|
OnButton_Link();
|
|
return true;
|
|
}
|
|
return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
|
|
}
|
|
|
|
void CLinkDialog::OnButton_SetPath(bool to)
|
|
{
|
|
UString currentPath;
|
|
NWindows::NControl::CComboBox &combo = to ?
|
|
_pathToCombo :
|
|
_pathFromCombo;
|
|
combo.GetText(currentPath);
|
|
// UString title = L"Specify a location for output folder";
|
|
UString title = LangString(IDS_SET_FOLDER);
|
|
|
|
UString resultPath;
|
|
if (!MyBrowseForFolder(*this, title, currentPath, resultPath))
|
|
return;
|
|
NFile::NName::NormalizeDirPathPrefix(resultPath);
|
|
combo.SetCurSel(-1);
|
|
combo.SetText(resultPath);
|
|
}
|
|
|
|
void CLinkDialog::ShowError(const wchar_t *s)
|
|
{
|
|
::MessageBoxW(*this, s, L"7-Zip", MB_ICONERROR);
|
|
}
|
|
|
|
void CLinkDialog::ShowLastErrorMessage()
|
|
{
|
|
ShowError(NError::MyFormatMessage(GetLastError()));
|
|
}
|
|
|
|
void CLinkDialog::OnButton_Link()
|
|
{
|
|
UString from, to;
|
|
_pathFromCombo.GetText(from);
|
|
_pathToCombo.GetText(to);
|
|
int i;
|
|
for (i = 0; i < ARRAY_SIZE(k_LinkType_Buttons); i++)
|
|
if (IsButtonCheckedBool(k_LinkType_Buttons[i]))
|
|
break;
|
|
if (i >= ARRAY_SIZE(k_LinkType_Buttons))
|
|
return;
|
|
|
|
int idb = k_LinkType_Buttons[i];
|
|
|
|
NFile::NFind::CFileInfo info1, info2;
|
|
bool finded1 = info1.Find(us2fs(from));
|
|
bool finded2 = info2.Find(us2fs(to));
|
|
|
|
bool isDirLink = (
|
|
idb == IDR_LINK_TYPE_SYM_DIR ||
|
|
idb == IDR_LINK_TYPE_JUNCTION);
|
|
|
|
if (finded1 && info1.IsDir() != isDirLink ||
|
|
finded2 && info2.IsDir() != isDirLink)
|
|
{
|
|
ShowError(L"Incorrect linkType");
|
|
return;
|
|
}
|
|
|
|
if (idb == IDR_LINK_TYPE_HARD)
|
|
{
|
|
bool res = NFile::NDir::MyCreateHardLink(us2fs(from), us2fs(to));
|
|
if (!res)
|
|
{
|
|
ShowLastErrorMessage();
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bool isSymLink = (idb != IDR_LINK_TYPE_JUNCTION);
|
|
|
|
CByteBuffer data;
|
|
if (!FillLinkData(data, to, isSymLink))
|
|
{
|
|
ShowError(L"Incorrect link");
|
|
return;
|
|
}
|
|
|
|
CReparseAttr attr;
|
|
if (!attr.Parse(data, data.Size()))
|
|
{
|
|
ShowError(L"Internal conversion error");
|
|
return;
|
|
}
|
|
|
|
|
|
if (!NFile::NIO::SetReparseData(us2fs(from), isDirLink, data, (DWORD)data.Size()))
|
|
{
|
|
ShowLastErrorMessage();
|
|
}
|
|
}
|
|
|
|
End(IDOK);
|
|
}
|
|
|
|
void CApp::Link()
|
|
{
|
|
int srcPanelIndex = GetFocusedPanelIndex();
|
|
CPanel &srcPanel = Panels[srcPanelIndex];
|
|
if (!srcPanel.IsFSFolder())
|
|
{
|
|
srcPanel.MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED);
|
|
return;
|
|
}
|
|
CRecordVector<UInt32> indices;
|
|
srcPanel.GetOperatedItemIndices(indices);
|
|
if (indices.IsEmpty())
|
|
return;
|
|
if (indices.Size() != 1)
|
|
{
|
|
srcPanel.MessageBoxErrorLang(IDS_SELECT_ONE_FILE);
|
|
return;
|
|
}
|
|
int index = indices[0];
|
|
const UString itemName = srcPanel.GetItemName(index);
|
|
|
|
UString srcPath = srcPanel._currentFolderPrefix + srcPanel.GetItemPrefix(index);
|
|
UString path = srcPath;
|
|
{
|
|
int destPanelIndex = (NumPanels <= 1) ? srcPanelIndex : (1 - srcPanelIndex);
|
|
CPanel &destPanel = Panels[destPanelIndex];
|
|
if (NumPanels > 1)
|
|
if (destPanel.IsFSFolder())
|
|
path = destPanel._currentFolderPrefix;
|
|
}
|
|
|
|
CLinkDialog dlg;
|
|
dlg.FilePath = srcPath + itemName;
|
|
dlg.AnotherPath = path;
|
|
|
|
if (dlg.Create(srcPanel.GetParent()) != IDOK)
|
|
return;
|
|
|
|
RefreshTitleAlways();
|
|
}
|