const wchar_t *PointToNameUNC(const wchar_t *lpwszPath) { if (!lpwszPath) return nullptr; if (IsSlash(lpwszPath[0]) && IsSlash(lpwszPath[1])) { lpwszPath+=2; for (int i=0; i<2; i++) { while (*lpwszPath && !IsSlash(*lpwszPath)) lpwszPath++; if (*lpwszPath) lpwszPath++; } } const wchar_t *lpwszNamePtr = lpwszPath; while (*lpwszPath) { if (IsSlash(*lpwszPath) || (*lpwszPath==L':' && lpwszPath == lpwszNamePtr+1)) lpwszNamePtr = lpwszPath+1; lpwszPath++; } return lpwszNamePtr; }
string &CutToNameUNC(string &strPath) { wchar_t *lpwszPath = strPath.GetBuffer(); if (IsSlash(lpwszPath[0]) && IsSlash(lpwszPath[1])) { lpwszPath+=2; for (int i=0; i<2; i++) { while (*lpwszPath && !IsSlash(*lpwszPath)) lpwszPath++; if (*lpwszPath) lpwszPath++; } } wchar_t *lpwszNamePtr = lpwszPath; while (*lpwszPath) { if (IsSlash(*lpwszPath) || (*lpwszPath==L':' && lpwszPath == lpwszNamePtr+1)) lpwszNamePtr = lpwszPath+1; lpwszPath++; } *lpwszNamePtr = 0; strPath.ReleaseBuffer(); return strPath; }
const wchar_t* PointToExt(const wchar_t *lpwszPath,const wchar_t *lpwszEndPtr) { if (!lpwszPath || !lpwszEndPtr) return nullptr; const wchar_t *lpwszExtPtr = lpwszEndPtr; while (lpwszExtPtr != lpwszPath) { if (*lpwszExtPtr==L'.') { if (IsSlash(*(lpwszExtPtr-1)) || *(lpwszExtPtr-1)==L':') return lpwszEndPtr; else return lpwszExtPtr; } if (IsSlash(*lpwszExtPtr) || *lpwszExtPtr==L':') return lpwszEndPtr; lpwszExtPtr--; } return lpwszEndPtr; }
const wchar_t* PointToName(const wchar_t *lpwszPath,const wchar_t *lpwszEndPtr) { if (!lpwszPath) return nullptr; if (*lpwszPath && *(lpwszPath+1)==L':') lpwszPath+=2; const wchar_t *lpwszNamePtr = lpwszEndPtr; if (!lpwszNamePtr) { lpwszNamePtr=lpwszPath; while (*lpwszNamePtr) lpwszNamePtr++; } while (lpwszNamePtr != lpwszPath) { if (IsSlash(*lpwszNamePtr)) return lpwszNamePtr+1; lpwszNamePtr--; } if (IsSlash(*lpwszPath)) return lpwszPath+1; else return lpwszPath; }
void DeleteDirTree(const wchar_t *Dir) { if (!*Dir || (IsSlash(Dir[0]) && !Dir[1]) || (Dir[1]==L':' && IsSlash(Dir[2]) && !Dir[3])) return; string strFullName; FAR_FIND_DATA_EX FindData; ScanTree ScTree(TRUE,TRUE,FALSE); ScTree.SetFindPath(Dir,L"*",0); while (ScTree.GetNextName(&FindData, strFullName)) { apiSetFileAttributes(strFullName,FILE_ATTRIBUTE_NORMAL); if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (ScTree.IsDirSearchDone()) apiRemoveDirectory(strFullName); } else apiDeleteFile(strFullName); } apiSetFileAttributes(Dir,FILE_ATTRIBUTE_NORMAL); apiRemoveDirectory(Dir); }
void FileList::GetDeltaToCurrent(FileList *input, FileList *output, const char *dirSubset, const char *remoteSubdir) { // For all files in this list that do not match the input list, write them to the output list. // dirSubset allows checking only a portion of the files in this list. unsigned thisIndex, inputIndex; unsigned dirSubsetLen, localPathLen, remoteSubdirLen; bool match; if (dirSubset) dirSubsetLen = (unsigned int) strlen(dirSubset); else dirSubsetLen = 0; if (remoteSubdir && remoteSubdir[0]) { remoteSubdirLen = (unsigned int) strlen(remoteSubdir); if (IsSlash(remoteSubdir[remoteSubdirLen - 1])) remoteSubdirLen--; } else remoteSubdirLen = 0; for (thisIndex = 0; thisIndex < fileList.Size(); thisIndex++) { localPathLen = (unsigned int) fileList[thisIndex].filename.GetLength(); while (localPathLen > 0) { if (IsSlash(fileList[thisIndex].filename[localPathLen - 1])) { localPathLen--; break; } localPathLen--; } // fileList[thisIndex].filename has to match dirSubset and be shorter or equal to it in length. if (dirSubsetLen > 0 && (localPathLen < dirSubsetLen || _strnicmp(fileList[thisIndex].filename.C_String(), dirSubset, dirSubsetLen) != 0 || (localPathLen > dirSubsetLen && IsSlash(fileList[thisIndex].filename[dirSubsetLen]) == false))) continue; match = false; for (inputIndex = 0; inputIndex < input->fileList.Size(); inputIndex++) { // If the filenames, hashes, and lengths match then skip this element in fileList. Otherwise write it to output if (_stricmp(input->fileList[inputIndex].filename.C_String() + remoteSubdirLen, fileList[thisIndex].filename.C_String() + dirSubsetLen) == 0) { match = true; if (input->fileList[inputIndex].fileLengthBytes == fileList[thisIndex].fileLengthBytes && input->fileList[inputIndex].dataLengthBytes == fileList[thisIndex].dataLengthBytes && memcmp(input->fileList[inputIndex].data, fileList[thisIndex].data, (size_t) fileList[thisIndex].dataLengthBytes) == 0) { // File exists on both machines and is the same. break; } else { // File exists on both machines and is not the same. output->AddFile(fileList[thisIndex].filename, fileList[thisIndex].fullPathToFile, 0, 0, fileList[thisIndex].fileLengthBytes, FileListNodeContext(0, 0), false); break; } } } if (match == false) { // Other system does not have the file at all output->AddFile(fileList[thisIndex].filename, fileList[thisIndex].fullPathToFile, 0, 0, fileList[thisIndex].fileLengthBytes, FileListNodeContext(0, 0), false); } } }
const wchar_t *LastSlash(const wchar_t *String) { const wchar_t *Start = String; while (*String++) ; while (--String!=Start && !IsSlash(*String)) ; return IsSlash(*String)?String:nullptr; }
const wchar_t *FirstSlash(const wchar_t *String) { do { if (IsSlash(*String)) return String; } while (*String++); return nullptr; }
bool IsRootPath(const string &Path) { size_t PathRootLen = GetPathRootLength(Path); if (Path.GetLength() == PathRootLen) return true; if (Path.GetLength() == PathRootLen + 1 && IsSlash(Path[Path.GetLength() - 1])) return true; return false; }
bool FindSlash(size_t &Pos, const string &Str, size_t StartPos) { for (size_t p = StartPos; p < Str.GetLength(); p++) { if (IsSlash(Str[p])) { Pos = p; return true; } } return false; }
bool FindLastSlash(size_t &Pos, const string &Str) { for (size_t p = Str.GetLength(); p > 0; p--) { if (IsSlash(Str[p - 1])) { Pos = p - 1; return true; } } return false; }
bool DeleteEndSlash(wchar_t *Path, bool AllEndSlash) { bool Ret = false; size_t len = StrLength(Path); while (len && IsSlash(Path[--len])) { Ret = true; Path[len] = L'\0'; if (!AllEndSlash) break; } return Ret; }
wchar_t* WINAPI TruncPathStr(wchar_t *Str, int MaxLength) { assert(MaxLength >= 0); MaxLength=Max(0, MaxLength); if (Str) { int nLength = (int)wcslen(Str); if ((MaxLength > 0) && (nLength > MaxLength) && (nLength >= 2)) { wchar_t *lpStart = nullptr; if (*Str && (Str[1] == L':') && IsSlash(Str[2])) lpStart = Str+3; else { if ((Str[0] == L'\\') && (Str[1] == L'\\')) { if ((lpStart = const_cast<wchar_t*>(FirstSlash(Str+2))) ) { wchar_t *lpStart2=lpStart; if ((lpStart-Str < nLength) && ((lpStart=const_cast<wchar_t*>(FirstSlash(lpStart2+1))))) lpStart++; } } } if (!lpStart || (lpStart-Str > MaxLength-5)) return TruncStr(Str, MaxLength); wchar_t *lpInPos = lpStart+3+(nLength-MaxLength); wmemmove(lpStart+3, lpInPos, (wcslen(lpInPos)+1)); wmemcpy(lpStart, L"...", 3); } } return Str; }
// Аналог PointToName, только для строк типа // "name\" (оканчивается на слеш) возвращает указатель на name, а не на пустую // строку const wchar_t* PointToFolderNameIfFolder(const wchar_t *Path) { if (!Path) return nullptr; const wchar_t *NamePtr=Path, *prevNamePtr=Path; while (*Path) { if (IsSlash(*Path) || (*Path==L':' && Path==NamePtr+1)) { prevNamePtr=NamePtr; NamePtr=Path+1; } ++Path; } return ((*NamePtr)?NamePtr:prevNamePtr); }
void CreatePath(const string &InputPath, bool Simple) { string Path(InputPath); ConvertNameToFull(InputPath, Path); size_t DirOffset = 0; ParsePath(Path, &DirOffset); string Part; Part.reserve(Path.size()); for (size_t i = DirOffset; i <= Path.size(); ++i) { if (i == Path.size() || IsSlash(Path[i])) { Part = Path.substr(0, i); if (!api::fs::exists(Part)) { if(api::CreateDirectory(Part, nullptr) && !Simple) TreeList::AddTreeName(Part); } } } }
BOOL DeleteEndSlash(string &strPath, bool AllEndSlash) { BOOL Ret=FALSE; if (!strPath.IsEmpty()) { size_t len=strPath.GetLength(); wchar_t *lpwszPath = strPath.GetBuffer(); while (len && IsSlash(lpwszPath[--len])) { Ret=TRUE; lpwszPath[len] = L'\0'; if (!AllEndSlash) break; } strPath.ReleaseBuffer(); } return Ret; }
string &CutToFolderNameIfFolder(string &strPath) { wchar_t *lpwszPath = strPath.GetBuffer(); wchar_t *lpwszNamePtr=lpwszPath, *lpwszprevNamePtr=lpwszPath; while (*lpwszPath) { if (IsSlash(*lpwszPath) || (*lpwszPath==L':' && lpwszPath==lpwszNamePtr+1)) { lpwszprevNamePtr=lpwszNamePtr; lpwszNamePtr=lpwszPath+1; } ++lpwszPath; } if (*lpwszNamePtr) *lpwszNamePtr=0; else *lpwszprevNamePtr=0; strPath.ReleaseBuffer(); return strPath; }
void ShellMakeDir(Panel *SrcPanel) { string strDirName; string strOriginalDirName; wchar_t *lpwszDirName; UserDefinedList DirList(0,0,ULF_UNIQUE); DialogDataEx MkDirDlgData[]= { DI_DOUBLEBOX,3,1,72,8,0,0,MSG(MMakeFolderTitle), DI_TEXT, 5,2, 0,2,0,0,MSG(MCreateFolder), DI_EDIT, 5,3,70,3,(DWORD_PTR)L"NewFolder",DIF_FOCUS|DIF_EDITEXPAND|DIF_HISTORY|DIF_USELASTHISTORY|DIF_EDITPATH,L"", DI_TEXT, 0,4, 0,4,0,DIF_SEPARATOR,L"", DI_CHECKBOX, 5,5, 0,5,Opt.MultiMakeDir,0,MSG(MMultiMakeDir), DI_TEXT, 0,6, 0,6,0,DIF_SEPARATOR,L"", DI_BUTTON, 0,7, 0,7,0,DIF_DEFAULT|DIF_CENTERGROUP,MSG(MOk), DI_BUTTON, 0,7, 0,7,0,DIF_CENTERGROUP,MSG(MCancel), }; MakeDialogItemsEx(MkDirDlgData,MkDirDlg); Dialog Dlg(MkDirDlg,ARRAYSIZE(MkDirDlg),MkDirDlgProc,reinterpret_cast<LONG_PTR>(&DirList)); Dlg.SetPosition(-1,-1,76,10); Dlg.SetHelp(L"MakeFolder"); Dlg.SetId(MakeFolderId); Dlg.Process(); if (Dlg.GetExitCode()==MKDIR_OK) { strDirName=MkDirDlg[MKDIR_EDIT].strData; const wchar_t *OneDir; DirList.Reset(); while (nullptr!=(OneDir=DirList.GetNext())) { strDirName = OneDir; strOriginalDirName = strDirName; //Unquote(DirName); if (Opt.CreateUppercaseFolders && !IsCaseMixed(strDirName)) strDirName.Upper(); DeleteEndSlash(strDirName,true); lpwszDirName = strDirName.GetBuffer(); bool bSuccess = false; if(HasPathPrefix(lpwszDirName)) { lpwszDirName += 4; } for (wchar_t *ChPtr=lpwszDirName; *ChPtr; ChPtr++) { if (IsSlash(*ChPtr)) { WCHAR Ch = ChPtr[1]; ChPtr[1] = 0; if (*lpwszDirName && (apiGetFileAttributes(lpwszDirName) == INVALID_FILE_ATTRIBUTES) && apiCreateDirectory(lpwszDirName,nullptr)) { TreeList::AddTreeName(lpwszDirName); bSuccess = true; } ChPtr[1] = Ch; } } strDirName.ReleaseBuffer(); BOOL bSuccess2; bool bSkip=false; while (!(bSuccess2=apiCreateDirectory(strDirName,nullptr))) { int LastError=GetLastError(); if (LastError==ERROR_ALREADY_EXISTS || LastError==ERROR_BAD_PATHNAME || LastError==ERROR_INVALID_NAME || LastError == ERROR_DIRECTORY) { int ret; if (DirList.IsEmpty()) ret=Message(MSG_WARNING|MSG_ERRORTYPE,1,MSG(MError),MSG(MCannotCreateFolder),strOriginalDirName,MSG(MCancel)); else ret=Message(MSG_WARNING|MSG_ERRORTYPE,2,MSG(MError),MSG(MCannotCreateFolder),strOriginalDirName,MSG(MOk),MSG(MSkip)); bSkip = ret==1; if (bSuccess || bSkip) break; else return; } else { int ret; if (DirList.IsEmpty()) { ret=Message(MSG_WARNING|MSG_ERRORTYPE,2,MSG(MError),MSG(MCannotCreateFolder),strOriginalDirName,MSG(MRetry),MSG(MCancel)); } else { ret=Message(MSG_WARNING|MSG_ERRORTYPE,3,MSG(MError),MSG(MCannotCreateFolder),strOriginalDirName,MSG(MRetry),MSG(MSkip),MSG(MCancel)); bSkip = ret==1; } if (ret) { if (bSuccess || bSkip) break; else return; } } } if (bSuccess2) TreeList::AddTreeName(strDirName); else if (!bSkip) break; } 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(); } } }
static void MixToFullPath(string& strPath) { //Skip all path to root (with slash if exists) size_t DirOffset = 0; ParsePath(strPath, &DirOffset); //Process "." and ".." if exists for (size_t Pos = DirOffset; Pos < strPath.size();) { //fragment "." if (strPath[Pos] == L'.' && (!Pos || IsSlash(strPath[Pos - 1]))) { //fragment "." at the end if(strPath.size() == Pos + 1) { strPath.resize(Pos); // don't change x:\ to x: if (strPath[Pos - 2] != L':') { strPath.pop_back(); } continue; } switch (strPath[Pos + 1]) { //fragment ".\" case L'\\': //fragment "./" case L'/': strPath.erase(Pos, 2); continue; //fragment "..\" or "../" or ".." at the end case L'.': { if (Pos + 2 == strPath.size() || IsSlash(strPath[Pos + 2])) { //Calculate subdir name offset size_t n = strPath.find_last_of(L"\\/", Pos-2); n = (n == string::npos || n < DirOffset) ? DirOffset : n+1; //fragment "..\" or "../" if (Pos + 2 < strPath.size()) { strPath.erase(n, Pos + 3 - n); } //fragment ".." at the end else { strPath.resize(n); } Pos = n; continue; } } break; } } ++Pos; } }
// Косметические преобразования строки пути. // CheckFullPath используется в FCTL_SET[ANOTHER]PANELDIR void PrepareDiskPath(string &strPath, bool CheckFullPath) { // elevation not required during cosmetic operation SCOPED_ACTION(elevation::suppress); if (!strPath.empty()) { if (strPath.size() > 1 && (strPath[1]==L':' || (IsSlash(strPath[0]) && IsSlash(strPath[1])))) { ReplaceSlashToBackslash(strPath); bool DoubleSlash = strPath[1]==L'\\'; while(ReplaceStrings(strPath, L"\\\\"sv, L"\\"sv)) ; if(DoubleSlash) { strPath = L'\\' + strPath; } if (CheckFullPath) { strPath = ConvertNameToFull(strPath); size_t DirOffset = 0; const auto Type = ParsePath(strPath, &DirOffset); if (Type == root_type::unknown && HasPathPrefix(strPath)) { DirOffset = 4; } size_t StartPos = DirOffset; if (StartPos < strPath.size()) { string TmpStr; TmpStr.reserve(strPath.size()); size_t LastPos = StartPos; const auto EndsWithSlash = IsSlash(strPath.back()); for (size_t i = StartPos; i <= strPath.size(); ++i) { if ((i < strPath.size() && IsSlash(strPath[i])) || (i == strPath.size() && !EndsWithSlash)) { TmpStr.assign(strPath, 0, i); os::fs::find_data fd; if (os::fs::get_find_data(TmpStr, fd)) { strPath.replace(LastPos, i - LastPos, fd.FileName); i += fd.FileName.size() - (i - LastPos); } if (i != strPath.size()) { LastPos = i + 1; } } } } } if (ParsePath(strPath) == root_type::drive_letter) { strPath[0] = upper(strPath[0]); } } } }
static void MixToFullPath(const string_view stPath, string& Dest, const string_view stCurrentDir) { string strDest; string_view pstCurrentDir; bool blIgnore = false; size_t PathDirOffset = 0; const auto PathType = ParsePath(stPath, &PathDirOffset); size_t PathOffset = PathDirOffset; switch (PathType) { case root_type::unknown: { if (HasPathPrefix(stPath)) // \\?\<ANY_UNKNOWN_FORMAT> { blIgnore = true; } else if (!stPath.empty() && IsSlash(stPath.front())) //"\" or "\abc" { ++PathOffset; if (!stCurrentDir.empty()) { size_t CurDirDirOffset = 0; if (ParsePath(stCurrentDir, &CurDirDirOffset) != root_type::unknown) { assign(strDest, stCurrentDir.substr(0, CurDirDirOffset)); } } } else //"abc" or whatever { pstCurrentDir = stCurrentDir; } } break; case root_type::drive_letter: //"C:" or "C:abc" { if(stPath.size() > 2 && IsSlash(stPath[2])) { PathOffset = 0; } else { const auto Drive = os::fs::get_drive(stPath[0]); const auto Value = os::env::get(L'=' + Drive); if (!Value.empty()) { strDest = Value; } else { if (upper(stPath[0])==upper(stCurrentDir[0])) { assign(strDest, stCurrentDir); } else { strDest = Drive; } } AddEndSlash(strDest); } } break; case root_type::remote: //"\\abc" { PathOffset = 0; } break; case root_type::unc_drive_letter: //"\\?\whatever" case root_type::unc_remote: case root_type::volume: case root_type::pipe: { blIgnore=true; PathOffset = 0; } break; } if (!pstCurrentDir.empty()) { append(strDest, pstCurrentDir); AddEndSlash(strDest); } append(strDest, stPath.substr(PathOffset)); if (!blIgnore && !HasPathPrefix(strDest)) MixToFullPath(strDest); Dest = std::move(strDest); }
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; }
PATH_TYPE ParsePath(const wchar_t* path, const wchar_t** DirPtr, bool* Root) { PATH_TYPE Result = PATH_UNKNOWN; static struct { PATH_TYPE Type; const wchar_t* REStr; RegExp re; bool Compiled; } PathTypes[] = { // x:<whatever> {PATH_DRIVELETTER, L"/(^.\\:)/"}, // \\?\x: or \\?\x:\ or \\?\x:\<whatever> {PATH_DRIVELETTERUNC, L"/(^\\\\{2}[\\?\\.]\\\\.\\:)(?:[\\\\\\/]|$)/"}, // \\server\share or \\server\share\ or \\server\share<whatever> {PATH_REMOTE, L"/(^\\\\{2}[^ \\\\\\/\\?\\.][^ \\\\\\/\\?]+?\\\\[^\\\\\\/]+?)(?:[\\\\\\/]|$)/"}, // \\?\unc\server\share or \\?\unc\server\share\ or \\?\unc\server\share<whatever> {PATH_REMOTEUNC, L"/(^\\\\{2}[\\?\\.]\\\\unc\\\\[^ \\\\\\/]+?\\\\[^\\\\\\/]+?)(?:[\\\\\\/]|$)/"}, // \\?\Volume{GUID} or \\?\Volume{GUID}\ or \\?\Volume{GUID}<whatever> {PATH_VOLUMEGUID, L"/(^\\\\{2}[\\?\\.]\\\\volume\\{[0-9A-Fa-f]{8}-(?:[0-9A-Fa-f]{4}-){3}[0-9A-Fa-f]{12}\\})(?:[\\\\\\/]|$)/"}, // \\?\pipe\ or \\?\pipe {PATH_PIPE, L"/(^\\\\{2}[\\?\\.]\\\\pipe)(?:[\\\\\\/]|$)/"}, }; static bool REInit = false; if(!REInit) { for(size_t i = 0; i < ARRAYSIZE(PathTypes); ++i) { PathTypes[i].Compiled = PathTypes[i].re.Compile(PathTypes[i].REStr, OP_PERLSTYLE|OP_OPTIMIZE|OP_IGNORECASE) != 0; assert(PathTypes[i].Compiled); } REInit = true; } SMatch m[3]; for(size_t i = 0; i < ARRAYSIZE(PathTypes); ++i) { if(PathTypes[i].Compiled) { int n = PathTypes[i].re.GetBracketsCount(); if(PathTypes[i].re.Search(path, m, n)) { if(DirPtr) { *DirPtr = path+m[1].end; } if(Root) { *Root = !path[m[1].end] || (IsSlash(path[m[1].end]) && !path[m[1].end+1]); } Result = PathTypes[i].Type; break; } } } return Result; }
bool PathStartsWith(const string &Path, const string &Start) { string PathPart(Start); DeleteEndSlash(PathPart, true); return Path.IsSubStrAt(0, PathPart) && (Path.GetLength() == PathPart.GetLength() || IsSlash(Path[PathPart.GetLength()])); }
BOOL AddEndSlash(wchar_t *Path, wchar_t TypeSlash) { BOOL Result=FALSE; if (Path) { /* $ 06.12.2000 IS ! Теперь функция работает с обоими видами слешей, также происходит изменение уже существующего конечного слеша на такой, который встречается чаще. */ wchar_t *end; int Slash=0, BackSlash=0; if (!TypeSlash) { end=Path; while (*end) { Slash+=(*end==L'\\'); BackSlash+=(*end==L'/'); end++; } } else { end=Path+StrLength(Path); if (TypeSlash == L'\\') Slash=1; else BackSlash=1; } int Length=(int)(end-Path); char c=(Slash<BackSlash)?L'/':L'\\'; Result=TRUE; if (!Length) { *end=c; end[1]=0; } else { end--; if (!IsSlash(*end)) { end[1]=c; end[2]=0; } else { *end=c; } } } return Result; }
bool IsAbsolutePath(const wchar_t *Path) { PATH_TYPE Type = ParsePath(Path); return Type == PATH_DRIVELETTERUNC || Type == PATH_REMOTE || Type == PATH_REMOTEUNC || Type == PATH_VOLUMEGUID || (Type == PATH_DRIVELETTER && (IsSlash(Path[2]) || !Path[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(); } } }
bool TestCurrentFolderName(const wchar_t *Name) { return Name[0] == L'.' && (!Name[1] || (IsSlash(Name[1]) && !Name[2])); }