Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'CPP/7zip/UI/FileManager/LinkDialog.cpp')
-rw-r--r--CPP/7zip/UI/FileManager/LinkDialog.cpp342
1 files changed, 342 insertions, 0 deletions
diff --git a/CPP/7zip/UI/FileManager/LinkDialog.cpp b/CPP/7zip/UI/FileManager/LinkDialog.cpp
new file mode 100644
index 00000000..a24ec601
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/LinkDialog.cpp
@@ -0,0 +1,342 @@
+// 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();
+}