bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName) { #if defined(SAVE_LINKS) && defined(_UNIX) // For RAR 3.x archives we process links even in test mode to skip link data. if (Arc.Format==RARFMT15) return ExtractUnixLink30(Cmd,DataIO,Arc,LinkName); if (Arc.Format==RARFMT50) return ExtractUnixLink50(Cmd,LinkName,&Arc.FileHead); #elif defined _WIN_ALL // RAR 5.0 archives store link information in file header, so there is // no need to additionally test it if we do not create a file. if (Arc.Format==RARFMT50) return CreateReparsePoint(Cmd,LinkName,&Arc.FileHead); #endif return false; }
void ShellMakeDir(Panel *SrcPanel) { FarList ComboList={sizeof(FarList)}; FarListItem LinkTypeItems[3]={}; ComboList.ItemsNumber=ARRAYSIZE(LinkTypeItems); ComboList.Items=LinkTypeItems; ComboList.Items[0].Text=MSG(MMakeFolderLinkNone); ComboList.Items[1].Text=MSG(MMakeFolderLinkJunction); ComboList.Items[2].Text=MSG(MMakeFolderLinkSymlink); ComboList.Items[0].Flags|=LIF_SELECTED; #if 1 //Maximus: поддержка "узких" дисплеев if (ScrX < 10) { _ASSERTE(ScrX>=10); return; } int BorderW = (72<(ScrX-1))?72:(ScrX-1); // 72 int ElemW = BorderW - 2; // 70 #endif FarDialogItem MkDirDlgData[]= { #if 1 //Maximus: поддержка "узких" дисплеев {DI_DOUBLEBOX,3,1,BorderW,10,0,nullptr,nullptr,0,MSG(MMakeFolderTitle)}, #else {DI_DOUBLEBOX,3,1,72,10,0,nullptr,nullptr,0,MSG(MMakeFolderTitle)}, #endif {DI_TEXT, 5,2, 0,2,0,nullptr,nullptr,0,MSG(MCreateFolder)}, #if 1 //Maximus: поддержка "узких" дисплеев {DI_EDIT, 5,3,ElemW,3,0,L"NewFolder",nullptr,DIF_FOCUS|DIF_EDITEXPAND|DIF_HISTORY|DIF_USELASTHISTORY|DIF_EDITPATH,L""}, #else {DI_EDIT, 5,3,70,3,0,L"NewFolder",nullptr,DIF_FOCUS|DIF_EDITEXPAND|DIF_HISTORY|DIF_USELASTHISTORY|DIF_EDITPATH,L""}, #endif {DI_TEXT, -1,4, 0,4,0,nullptr,nullptr,DIF_SEPARATOR,L""}, {DI_TEXT, 5,5, 0,5,0,nullptr,nullptr,0,MSG(MMakeFolderLinkType)}, #if 1 //Maximus: поддержка "узких" дисплеев {DI_COMBOBOX,20,5,ElemW,5,0,nullptr,nullptr,DIF_DROPDOWNLIST|DIF_LISTNOAMPERSAND|DIF_LISTWRAPMODE,L""}, #else {DI_COMBOBOX,20,5,70,5,0,nullptr,nullptr,DIF_DROPDOWNLIST|DIF_LISTNOAMPERSAND|DIF_LISTWRAPMODE,L""}, #endif {DI_TEXT, 5,6, 0,6,0,nullptr,nullptr,0,MSG(MMakeFolderLinkTarget)}, #if 1 //Maximus: поддержка "узких" дисплеев {DI_EDIT, 20,6,ElemW,6,0,L"NewFolderLinkTarget",nullptr,DIF_DISABLE|DIF_EDITEXPAND|DIF_HISTORY|DIF_USELASTHISTORY|DIF_EDITPATH,L""}, #else {DI_EDIT, 20,6,70,6,0,L"NewFolderLinkTarget",nullptr,DIF_DISABLE|DIF_EDITEXPAND|DIF_HISTORY|DIF_USELASTHISTORY|DIF_EDITPATH,L""}, #endif {DI_CHECKBOX, 5,7, 0,7,Global->Opt->MultiMakeDir,nullptr,nullptr,0,MSG(MMultiMakeDir)}, {DI_TEXT, -1,8, 0,8,0,nullptr,nullptr,DIF_SEPARATOR,L""}, {DI_BUTTON, 0,9, 0,9,0,nullptr,nullptr,DIF_DEFAULTBUTTON|DIF_CENTERGROUP,MSG(MOk)}, {DI_BUTTON, 0,9, 0,9,0,nullptr,nullptr,DIF_CENTERGROUP,MSG(MCancel)}, }; auto MkDirDlg = MakeDialogItemsEx(MkDirDlgData); MkDirDlg[MKDIR_COMBOBOX_LINKTYPE].ListItems=&ComboList; std::vector<string> DirList; auto Dlg = Dialog::create(MkDirDlg, MkDirDlgProc, &DirList); #if 1 //Maximus: поддержка "узких" дисплеев Dlg->SetPosition(-1,-1,BorderW+4,12); #else Dlg->SetPosition(-1,-1,76,12); #endif Dlg->SetHelp(L"MakeFolder"); Dlg->SetId(MakeFolderId); Dlg->Process(); if (Dlg->GetExitCode()==MKDIR_OK) { string strDirName=MkDirDlg[MKDIR_EDIT].strData; string strOriginalDirName; bool SkipAll = false; FOR(const auto& i, DirList) { // TODO: almost the same code in dirmix::CreatePath() strDirName = i; strOriginalDirName = strDirName; ConvertNameToFull(strDirName, strDirName); DeleteEndSlash(strDirName); bool bSuccess = false; size_t DirOffset = 0; ParsePath(strDirName, &DirOffset); string Part; Part.reserve(strDirName.size()); for (size_t j = DirOffset; j <= strDirName.size(); ++j) { if (j == strDirName.size() || IsSlash(strDirName[j])) { Part = strDirName.substr(0, j); if (!os::fs::exists(Part) || j == strDirName.size()) // skip all intermediate dirs, but not last. { while(!(bSuccess=(os::CreateDirectory(Part, nullptr)!=FALSE)) && !SkipAll) { Global->CatchError(); int Ret = OperationFailed(strOriginalDirName, MError, MSG(MCannotCreateFolder)); if(Ret == 1) // skip { break; } else if(Ret == 2) { SkipAll = true; break; } else if (Ret < 0 || Ret == 3) // cancel { return; } } if(bSuccess) { TreeList::AddTreeName(Part); } } } } if (bSuccess) { if(MkDirDlg[MKDIR_COMBOBOX_LINKTYPE].ListPos) { string strTarget=MkDirDlg[MKDIR_EDIT_LINKPATH].strData; Unquote(strTarget); while(!CreateReparsePoint(strTarget, strDirName, MkDirDlg[MKDIR_COMBOBOX_LINKTYPE].ListPos==1?RP_JUNCTION:RP_SYMLINKDIR) && !SkipAll) { Global->CatchError(); int Ret = OperationFailed(strDirName, MError, MSG(MCopyCannotCreateLink)); if(Ret == 1) // skip { break; } else if(Ret == 2) { SkipAll = true; break; } else if (Ret < 0 || Ret == 3) // cancel { return; } } } } }
// Кусок для создания SymLink для каталогов. int MkSymLink(const string& Target, const string& LinkName, ReparsePointTypes LinkType, bool Silent, bool HoldTarget) { if (!Target.empty() && !LinkName.empty()) { string strFullTarget; // выделим имя auto strSelOnlyName = Target; DeleteEndSlash(strSelOnlyName); const auto SlashPos = FindLastSlash(strSelOnlyName); const auto symlink = LinkType==RP_SYMLINK || LinkType==RP_SYMLINKFILE || LinkType==RP_SYMLINKDIR; if (Target[1] == L':' && (!Target[2] || (IsSlash(Target[2]) && !Target[3]))) // C: или C:/ { // if(Flags&FCOPY_VOLMOUNT) { strFullTarget = Target; AddEndSlash(strFullTarget); } /* Вот здесь - ну очень умное поведение! Т.е. если в качестве SelName передали "C:", то в этом куске происходит коррекция типа линка - с symlink`а на volmount */ LinkType=RP_VOLMOUNT; } else strFullTarget = ConvertNameToFull(Target); auto strFullLink = ConvertNameToFull(LinkName); if (IsSlash(strFullLink.back())) { if (LinkType != RP_VOLMOUNT) { const auto SelName = SlashPos != string::npos? string_view(strSelOnlyName).substr(SlashPos + 1) : string_view(strSelOnlyName); append(strFullLink, SelName); } else { append(strFullLink, L"Disk_"sv, Target.front()); } } if (LinkType==RP_VOLMOUNT) { AddEndSlash(strFullTarget); AddEndSlash(strFullLink); } if (symlink) { // в этом случае создается путь, но не сам каталог string strPath=strFullLink; if (CutToSlash(strPath)) { if (!os::fs::exists(strPath)) CreatePath(strPath); } } else { bool CreateDir=true; if (LinkType==RP_EXACTCOPY) { // в этом случае создается или каталог, или пустой файл if (os::fs::is_file(strFullTarget)) CreateDir=false; } if (CreateDir) { if (os::fs::create_directory(strFullLink)) TreeList::AddTreeName(strFullLink); else CreatePath(strFullLink); } else { string strPath=strFullLink; if (CutToSlash(strPath)) { if (!os::fs::exists(strPath)) CreatePath(strPath); os::fs::file(strFullLink, 0, 0, nullptr, CREATE_NEW, os::fs::get_file_attributes(strFullTarget)); } } if (!os::fs::exists(strFullLink)) { if (!Silent) { const auto ErrorState = error_state::fetch(); Message(MSG_WARNING, ErrorState, msg(lng::MError), { msg(lng::MCopyCannotCreateLink), strFullLink }, { lng::MOk }); } return 0; } } if (LinkType!=RP_VOLMOUNT) { if (CreateReparsePoint(HoldTarget && symlink ? Target : strFullTarget, strFullLink, LinkType)) { return 1; } else { if (!Silent) { const auto ErrorState = error_state::fetch(); Message(MSG_WARNING, ErrorState, msg(lng::MError), { msg(lng::MCopyCannotCreateLink), strFullLink }, { lng::MOk }); } return 0; } } else { if (CreateVolumeMountPoint(strFullTarget,strFullLink)) { return 1; } else { if (!Silent) { const auto ErrorState = error_state::fetch(); Message(MSG_WARNING, ErrorState, msg(lng::MError), { format(msg(lng::MCopyMountVolFailed), Target), format(msg(lng::MCopyMountVolFailed2), strFullLink) }, { lng::MOk }); } return 0; } } } return 2; }
// Кусок для создания SymLink для каталогов. int MkSymLink(const wchar_t *SelName,const wchar_t *Dest,ReparsePointTypes LinkType,DWORD Flags) { if (SelName && *SelName && Dest && *Dest) { string strSrcFullName, strDestFullName, strSelOnlyName; string strMsgBuf, strMsgBuf2; // выделим имя strSelOnlyName = SelName; DeleteEndSlash(strSelOnlyName); const wchar_t *PtrSelName=LastSlash(strSelOnlyName); if (!PtrSelName) PtrSelName=strSelOnlyName; else ++PtrSelName; if (SelName[1] == L':' && (!SelName[2] || (IsSlash(SelName[2]) && !SelName[3]))) // C: или C:/ { // if(Flags&FCOPY_VOLMOUNT) { strSrcFullName = SelName; AddEndSlash(strSrcFullName); } /* Вот здесь - ну очень умное поведение! Т.е. если в качестве SelName передали "C:", то в этом куске происходит коррекция типа линка - с symlink`а на volmount */ LinkType=RP_VOLMOUNT; } else ConvertNameToFull(SelName,strSrcFullName); ConvertNameToFull(Dest,strDestFullName); if (IsSlash(strDestFullName.At(strDestFullName.GetLength()-1))) { if (LinkType!=RP_VOLMOUNT) strDestFullName += PtrSelName; else { const wchar_t Tmp[]={L'D',L'i',L's',L'k',L'_',*SelName,L'\0'}; strDestFullName+=Tmp; } } if (LinkType==RP_VOLMOUNT) { AddEndSlash(strSrcFullName); AddEndSlash(strDestFullName); } DWORD JSAttr=apiGetFileAttributes(strDestFullName); if (JSAttr != INVALID_FILE_ATTRIBUTES) // Существует такой? { if ((JSAttr&FILE_ATTRIBUTE_DIRECTORY)!=FILE_ATTRIBUTE_DIRECTORY) { if (!(Flags&FCOPY_NOSHOWMSGLINK)) { Message(MSG_WARNING,1,MSG(MError), MSG(MCopyCannotCreateJunctionToFile), strDestFullName,MSG(MOk)); } return 0; } if (TestFolder(strDestFullName) == TSTFLD_NOTEMPTY) // а пустой? { // не пустой, ну что же, тогда пробуем сделать dest\srcname AddEndSlash(strDestFullName); if (LinkType==RP_VOLMOUNT) { string strTmpName; strTmpName.Format(MSG(MCopyMountName),*SelName); strDestFullName += strTmpName; AddEndSlash(strDestFullName); } else strDestFullName += PtrSelName; JSAttr=apiGetFileAttributes(strDestFullName); if (JSAttr != INVALID_FILE_ATTRIBUTES) // И такой тоже есть??? { if (TestFolder(strDestFullName) == TSTFLD_NOTEMPTY) // а пустой? { if (!(Flags&FCOPY_NOSHOWMSGLINK)) { if (LinkType==RP_VOLMOUNT) { strMsgBuf.Format(MSG(MCopyMountVolFailed), SelName); strMsgBuf2.Format(MSG(MCopyMountVolFailed2), strDestFullName.CPtr()); Message(MSG_WARNING,1,MSG(MError), strMsgBuf, strMsgBuf2, MSG(MCopyFolderNotEmpty), MSG(MOk)); } else Message(MSG_WARNING,1,MSG(MError), MSG(MCopyCannotCreateLink),strDestFullName, MSG(MCopyFolderNotEmpty),MSG(MOk)); } return 0; // однозначно в морг } } else // создаем. { if (apiCreateDirectory(strDestFullName,nullptr)) TreeList::AddTreeName(strDestFullName); else CreatePath(strDestFullName); } if (apiGetFileAttributes(strDestFullName) == INVALID_FILE_ATTRIBUTES) // так, все очень даже плохо. { if (!(Flags&FCOPY_NOSHOWMSGLINK)) { Message(MSG_WARNING|MSG_ERRORTYPE,1,MSG(MError), MSG(MCopyCannotCreateFolder), strDestFullName,MSG(MOk)); } return 0; } } } else { if (LinkType==RP_SYMLINK || LinkType==RP_SYMLINKFILE || LinkType==RP_SYMLINKDIR) { // в этом случае создается путь, но не сам каталог string strPath=strDestFullName; if (CutToSlash(strPath)) { if (apiGetFileAttributes(strPath)==INVALID_FILE_ATTRIBUTES) CreatePath(strPath); } } else { bool CreateDir=true; if (LinkType==RP_EXACTCOPY) { // в этом случае создается или каталог, или пустой файл DWORD dwSrcAttr=apiGetFileAttributes(strSrcFullName); if (dwSrcAttr!=INVALID_FILE_ATTRIBUTES && !(dwSrcAttr&FILE_ATTRIBUTE_DIRECTORY)) CreateDir=false; } if (CreateDir) { if (apiCreateDirectory(strDestFullName,nullptr)) TreeList::AddTreeName(strDestFullName); else CreatePath(strDestFullName); } else { string strPath=strDestFullName; if (CutToSlash(strPath)) { // создаём if (apiGetFileAttributes(strPath)==INVALID_FILE_ATTRIBUTES) CreatePath(strPath); File file; if(file.Open(strDestFullName, 0, 0, 0, CREATE_NEW, apiGetFileAttributes(strSrcFullName))) { file.Close(); } } } if (apiGetFileAttributes(strDestFullName) == INVALID_FILE_ATTRIBUTES) // так. все очень даже плохо. { if (!(Flags&FCOPY_NOSHOWMSGLINK)) { Message(MSG_WARNING|MSG_ERRORTYPE,1,MSG(MError), MSG(MCopyCannotCreateLink),strDestFullName,MSG(MOk)); } return 0; } } } if (LinkType!=RP_VOLMOUNT) { if (CreateReparsePoint(strSrcFullName,strDestFullName,LinkType)) { return 1; } else { if (!(Flags&FCOPY_NOSHOWMSGLINK)) { Message(MSG_WARNING|MSG_ERRORTYPE,1,MSG(MError), MSG(MCopyCannotCreateLink),strDestFullName,MSG(MOk)); } return 0; } } else { if (CreateVolumeMountPoint(strSrcFullName,strDestFullName)) { return 1; } else { if (!(Flags&FCOPY_NOSHOWMSGLINK)) { strMsgBuf.Format(MSG(MCopyMountVolFailed),SelName); strMsgBuf2.Format(MSG(MCopyMountVolFailed2),strDestFullName.CPtr()); Message(MSG_WARNING|MSG_ERRORTYPE,1,MSG(MError),strMsgBuf,strMsgBuf2,MSG(MOk)); } return 0; } } } return 2; }
void ShellMakeDir(Panel *SrcPanel) { FarList ComboList={sizeof(FarList)}; FarListItem LinkTypeItems[3]={}; ComboList.ItemsNumber=ARRAYSIZE(LinkTypeItems); ComboList.Items=LinkTypeItems; ComboList.Items[0].Text=MSG(MMakeFolderLinkNone); ComboList.Items[1].Text=MSG(MMakeFolderLinkJunction); ComboList.Items[2].Text=MSG(MMakeFolderLinkSymlink); ComboList.Items[0].Flags|=LIF_SELECTED; FarDialogItem MkDirDlgData[]= { {DI_DOUBLEBOX,3,1,72,10,0,nullptr,nullptr,0,MSG(MMakeFolderTitle)}, {DI_TEXT, 5,2, 0,2,0,nullptr,nullptr,0,MSG(MCreateFolder)}, {DI_EDIT, 5,3,70,3,0,L"NewFolder",nullptr,DIF_FOCUS|DIF_EDITEXPAND|DIF_HISTORY|DIF_USELASTHISTORY|DIF_EDITPATH,L""}, {DI_TEXT, 0,4, 0,4,0,nullptr,nullptr,DIF_SEPARATOR,L""}, {DI_TEXT, 5,5, 0,5,0,nullptr,nullptr,0,MSG(MMakeFolderLinkType)}, {DI_COMBOBOX,20,5,70,5,0,nullptr,nullptr,DIF_DROPDOWNLIST|DIF_LISTNOAMPERSAND|DIF_LISTWRAPMODE,L""}, {DI_TEXT, 5,6, 0,6,0,nullptr,nullptr,0,MSG(MMakeFolderLinkTarget)}, {DI_EDIT, 20,6,70,6,0,L"NewFolderLinkTarget",nullptr,DIF_DISABLE|DIF_EDITEXPAND|DIF_HISTORY|DIF_USELASTHISTORY|DIF_EDITPATH,L""}, {DI_CHECKBOX, 5,7, 0,7,Opt.MultiMakeDir,nullptr,nullptr,0,MSG(MMultiMakeDir)}, {DI_TEXT, 0,8, 0,8,0,nullptr,nullptr,DIF_SEPARATOR,L""}, {DI_BUTTON, 0,9, 0,9,0,nullptr,nullptr,DIF_DEFAULTBUTTON|DIF_CENTERGROUP,MSG(MOk)}, {DI_BUTTON, 0,9, 0,9,0,nullptr,nullptr,DIF_CENTERGROUP,MSG(MCancel)}, }; MakeDialogItemsEx(MkDirDlgData,MkDirDlg); MkDirDlg[MKDIR_COMBOBOX_LINKTYPE].ListItems=&ComboList; UserDefinedList DirList(ULF_UNIQUE); Dialog Dlg(MkDirDlg,ARRAYSIZE(MkDirDlg),MkDirDlgProc,&DirList); Dlg.SetPosition(-1,-1,76,12); Dlg.SetHelp(L"MakeFolder"); Dlg.SetId(MakeFolderId); Dlg.Process(); if (Dlg.GetExitCode()==MKDIR_OK) { string strDirName=MkDirDlg[MKDIR_EDIT].strData; string strOriginalDirName; const wchar_t *OneDir; DirList.Reset(); bool SkipAll = false; while (nullptr!=(OneDir=DirList.GetNext())) { strDirName = OneDir; strOriginalDirName = strDirName; //Unquote(DirName); if (Opt.CreateUppercaseFolders && !IsCaseMixed(strDirName)) strDirName.Upper(); DeleteEndSlash(strDirName,true); wchar_t* lpwszDirName = strDirName.GetBuffer(); bool bSuccess = false; wchar_t *ChPtr; if(ParsePath(lpwszDirName, const_cast<const wchar_t **>(&ChPtr)) == PATH_UNKNOWN) { ChPtr = lpwszDirName; } for (; ; ChPtr++) { if (IsSlash(*ChPtr) || !*ChPtr) { WCHAR Ch=0; if(*ChPtr) { Ch = ChPtr[1]; ChPtr[1] = 0; } if (*lpwszDirName) { string _strDirName(lpwszDirName); if (apiGetFileAttributes(_strDirName) == INVALID_FILE_ATTRIBUTES || !*ChPtr) // skip all intermediate dirs, but not last. { while(!(bSuccess=(apiCreateDirectory(_strDirName, nullptr)!=FALSE)) && !SkipAll) { int Ret = OperationFailed(strOriginalDirName, MError, MSG(MCannotCreateFolder)); if(Ret == 1) // skip { break; } else if(Ret == 2) { SkipAll = true; break; } else if (Ret < 0 || Ret == 3) // cancel { return; } } if(bSuccess) { TreeList::AddTreeName(_strDirName); } } } if(*ChPtr) { ChPtr[1] = Ch; } else { break; } } } strDirName.ReleaseBuffer(); if (bSuccess) { if(MkDirDlg[MKDIR_COMBOBOX_LINKTYPE].ListPos) { string strTarget=MkDirDlg[MKDIR_EDIT_LINKPATH].strData; Unquote(strTarget); while(!CreateReparsePoint(strTarget, strDirName, MkDirDlg[MKDIR_COMBOBOX_LINKTYPE].ListPos==1?RP_JUNCTION:RP_SYMLINKDIR) && !SkipAll) { int Ret = OperationFailed(strDirName, MError, MSG(MCopyCannotCreateLink)); if(Ret == 1) // skip { break; } else if(Ret == 2) { SkipAll = true; break; } else if (Ret < 0 || Ret == 3) // cancel { return; } } } TreeList::AddTreeName(strDirName); } } SrcPanel->Update(UPDATE_KEEP_SELECTION); if (!strDirName.IsEmpty()) { size_t pos; if (FindSlash(pos,strDirName)) strDirName.SetLength(pos); if (!SrcPanel->GoToFile(strDirName) && strDirName.At(strDirName.GetLength()-1)==L'.') { strDirName.SetLength(strDirName.GetLength()-1); SrcPanel->GoToFile(strDirName); } } SrcPanel->Redraw(); Panel *AnotherPanel=CtrlObject->Cp()->GetAnotherPanel(SrcPanel); int AnotherType=AnotherPanel->GetType(); if (AnotherPanel->NeedUpdatePanel(SrcPanel) || AnotherType==QVIEW_PANEL) { AnotherPanel->Update(UPDATE_KEEP_SELECTION|UPDATE_SECONDARY); AnotherPanel->Redraw(); } } }