void NTPath::Transform() { string& Data = *this; if (!Data.empty()) { if(!HasPathPrefix(Data)) { ConvertNameToFull(Data,Data); if (!HasPathPrefix(Data)) { ReplaceSlashToBackslash(Data); string Prefix(ParsePath(Data) == PATH_DRIVELETTER? L"\\\\?\\" : L"\\\\?\\UNC"); while(ReplaceStrings(Data,L"\\\\",L"\\")) ; Data=Prefix+Data; } } if(Data.size() > 5 && Data[5] == L':') { // "\\?\C:" -> "\\?\c:" // Some file operations fails on Win2k if a drive letter is in upper case ToLower(Data, 4, 1); } } }
bool ModifyReparsePoint(const wchar_t *Object,const wchar_t *NewData) { bool Result=false; LPBYTE szBuff=new BYTE[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; if(szBuff) { PREPARSE_DATA_BUFFER rdb=reinterpret_cast<PREPARSE_DATA_BUFFER>(szBuff); if (GetREPARSE_DATA_BUFFER(Object,rdb)) { bool FillResult=false; switch (rdb->ReparseTag) { case IO_REPARSE_TAG_MOUNT_POINT: { string strPrintName,strSubstituteName; ConvertNameToFull(NewData,strPrintName); strSubstituteName=L"\\??\\"; strSubstituteName+=(strPrintName.CPtr()+(HasPathPrefix(strPrintName)?4:0)); FillResult=FillREPARSE_DATA_BUFFER(rdb,strPrintName,strPrintName.GetLength(),strSubstituteName,strSubstituteName.GetLength()); } break; case IO_REPARSE_TAG_SYMLINK: { string strPrintName=NewData,strSubstituteName=NewData; if (IsAbsolutePath(NewData)) { strSubstituteName=L"\\??\\"; strSubstituteName+=(strPrintName.CPtr()+(HasPathPrefix(strPrintName)?4:0)); rdb->SymbolicLinkReparseBuffer.Flags=0; } else { rdb->SymbolicLinkReparseBuffer.Flags=SYMLINK_FLAG_RELATIVE; } FillResult=FillREPARSE_DATA_BUFFER(rdb,strPrintName,strPrintName.GetLength(),strSubstituteName,strSubstituteName.GetLength()); } break; } if (FillResult) { Result=SetREPARSE_DATA_BUFFER(Object,rdb); } else { SetLastError(ERROR_INSUFFICIENT_BUFFER); } } delete[] szBuff; } return Result; }
string ConvertNameToLong(string_view const Object) { string strDest; if (!os::fs::GetLongPathName(null_terminated(Object).c_str(), strDest)) { assign(strDest, Object); if (!HasPathPrefix(Object)) { if (os::fs::GetLongPathName(NTPath(Object), strDest)) { switch (ParsePath(strDest)) { case root_type::unc_drive_letter: strDest.erase(0, 4); // \\?\X:\path -> X:\path break; case root_type::unc_remote: strDest.erase(2, 6); // \\?\UNC\server -> \\server break; default: // should never happen break; } } } } return strDest; }
bool CutToSlash(string &strStr, bool bInclude) { size_t pos; if (FindLastSlash(pos,strStr)) { if (pos==3 && HasPathPrefix(strStr)) return false; if (bInclude) strStr.SetLength(pos); else strStr.SetLength(pos+1); return true; } return false; }
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(); } } }
// Косметические преобразования строки пути. // 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); }
bool WINAPI CreateReparsePoint(const wchar_t *Target, const wchar_t *Object,DWORD Type) { bool Result=false; if (Object && *Object && Target && *Target) { switch (Type) { case RP_EXACTCOPY: Result=DuplicateReparsePoint(Target,Object); break; case RP_SYMLINK: case RP_SYMLINKFILE: case RP_SYMLINKDIR: if(Type == RP_SYMLINK) { DWORD Attr = apiGetFileAttributes(Target); Type = ((Attr != INVALID_FILE_ATTRIBUTES) && (Attr&FILE_ATTRIBUTE_DIRECTORY)? RP_SYMLINKDIR : RP_SYMLINKFILE); } if (ifn.pfnCreateSymbolicLink) { Result=apiCreateSymbolicLink(Object,Target,Type==RP_SYMLINKDIR?SYMBOLIC_LINK_FLAG_DIRECTORY:0); } else { bool ObjectCreated=false; if (Type==RP_SYMLINKDIR) { ObjectCreated=apiCreateDirectory(Object,nullptr)!=FALSE; } else { File file; if(file.Open(Object,0,0,nullptr,CREATE_NEW)) { ObjectCreated=true; file.Close(); } } if (ObjectCreated) { LPBYTE szBuff=new BYTE[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; if(szBuff) { PREPARSE_DATA_BUFFER rdb=reinterpret_cast<PREPARSE_DATA_BUFFER>(szBuff); rdb->ReparseTag=IO_REPARSE_TAG_SYMLINK; string strPrintName=Target,strSubstituteName=Target; if (IsAbsolutePath(Target)) { strSubstituteName=L"\\??\\"; strSubstituteName+=(strPrintName.CPtr()+(HasPathPrefix(strPrintName)?4:0)); rdb->SymbolicLinkReparseBuffer.Flags=0; } else { rdb->SymbolicLinkReparseBuffer.Flags=SYMLINK_FLAG_RELATIVE; } if (FillREPARSE_DATA_BUFFER(rdb,strPrintName,strPrintName.GetLength(),strSubstituteName,strSubstituteName.GetLength())) { Result=SetREPARSE_DATA_BUFFER(Object,rdb); } else { SetLastError(ERROR_INSUFFICIENT_BUFFER); } delete[] szBuff; } } } break; case RP_JUNCTION: case RP_VOLMOUNT: { string strPrintName,strSubstituteName; ConvertNameToFull(Target,strPrintName); strSubstituteName=L"\\??\\"; strSubstituteName+=(strPrintName.CPtr()+(HasPathPrefix(strPrintName)?4:0)); BYTE szBuff[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; PREPARSE_DATA_BUFFER rdb=reinterpret_cast<PREPARSE_DATA_BUFFER>(szBuff); rdb->ReparseTag=IO_REPARSE_TAG_MOUNT_POINT; if (FillREPARSE_DATA_BUFFER(rdb,strPrintName,strPrintName.GetLength(),strSubstituteName,strSubstituteName.GetLength())) { Result=SetREPARSE_DATA_BUFFER(Object,rdb); } else { SetLastError(ERROR_INSUFFICIENT_BUFFER); } } break; } } return Result; }