bool GetVHDName(const string& DeviceName, string &strVolumePath) { bool Result=false; File Device; if(Device.Open(DeviceName, FILE_READ_ATTRIBUTES,FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, nullptr, OPEN_EXISTING)) { ULONG Size = 1024; PSTORAGE_DEPENDENCY_INFO StorageDependencyInfo = static_cast<PSTORAGE_DEPENDENCY_INFO>(xf_malloc(Size)); if(StorageDependencyInfo) { StorageDependencyInfo->Version = STORAGE_DEPENDENCY_INFO_VERSION_2; DWORD Used = 0; Result = Device.GetStorageDependencyInformation(GET_STORAGE_DEPENDENCY_FLAG_HOST_VOLUMES, Size, StorageDependencyInfo, &Used); if(!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { StorageDependencyInfo = static_cast<PSTORAGE_DEPENDENCY_INFO>(xf_realloc(StorageDependencyInfo, Used)); if(StorageDependencyInfo) { Result = Device.GetStorageDependencyInformation(GET_STORAGE_DEPENDENCY_FLAG_HOST_VOLUMES, Used, StorageDependencyInfo, &Used); } } if(Result) { if(StorageDependencyInfo->NumberEntries) { strVolumePath = StorageDependencyInfo->Version2Entries[0].HostVolumeName; strVolumePath += StorageDependencyInfo->Version2Entries[0].DependentVolumeRelativePath; // trick: ConvertNameToReal also converts \\?\{GUID} to drive letter, if possible. ConvertNameToReal(strVolumePath, strVolumePath); } } } } return Result; }
void ScanTree::SetFindPath(const wchar_t *Path,const wchar_t *Mask, const DWORD NewScanFlags) { ScanItems.Free(); ScanItems.addItem(); Flags.Clear(FSCANTREE_FILESFIRST); strFindMask = Mask; strFindPath = Path; ConvertNameToReal(strFindPath, ScanItems.lastItem()->RealPath); AddEndSlash(strFindPath); strFindPath += strFindMask; Flags.Set((Flags.Flags()&0x0000FFFF)|(NewScanFlags&0xFFFF0000)); }
string ConvertNameToUNC(string_view const Object) { auto strFileName = ConvertNameToFull(Object); // Посмотрим на тип файловой системы string strFileSystemName; os::fs::GetVolumeInformation(GetPathRoot(strFileName), nullptr, nullptr, nullptr, nullptr, &strFileSystemName); DWORD uniSize = 1024; block_ptr<UNIVERSAL_NAME_INFO> uni(uniSize); // применяем WNetGetUniversalName для чего угодно, только не для Novell`а if (!equal_icase(strFileSystemName, L"NWFS"sv)) { switch (WNetGetUniversalName(strFileName.c_str(), UNIVERSAL_NAME_INFO_LEVEL, uni.get(), &uniSize)) { case NO_ERROR: strFileName = uni->lpUniversalName; break; case ERROR_MORE_DATA: uni.reset(uniSize); if (WNetGetUniversalName(strFileName.c_str(),UNIVERSAL_NAME_INFO_LEVEL,uni.get(),&uniSize)==NO_ERROR) strFileName = uni->lpUniversalName; break; } } else if (strFileName.size() > 1 && strFileName[1] == L':') { // BugZ#449 - Неверная работа CtrlAltF с ресурсами Novell DS // Здесь, если не получилось получить UniversalName и если это // мапленный диск - получаем как для меню выбора дисков string strTemp; if (DriveLocalToRemoteName(DRIVE_UNKNOWN,strFileName[0],strTemp)) { const auto SlashPos = FindSlash(strFileName); if (SlashPos != string::npos) path::append(strTemp, string_view(strFileName).substr(SlashPos + 1)); strFileName = strTemp; } } return ConvertNameToReal(strFileName); }
bool GetVHDInfo(const string& DeviceName, string &strVolumePath, VIRTUAL_STORAGE_TYPE* StorageType) { const os::fs::file Device(DeviceName, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING); if (!Device) return false; block_ptr<STORAGE_DEPENDENCY_INFO> StorageDependencyInfo; const auto& InitStorage = [&](size_t Size) { StorageDependencyInfo.reset(Size); StorageDependencyInfo->Version = STORAGE_DEPENDENCY_INFO_VERSION_2; }; DWORD Size = 4096; for (;;) { InitStorage(Size); if (Device.GetStorageDependencyInformation(GET_STORAGE_DEPENDENCY_FLAG_HOST_VOLUMES, Size, StorageDependencyInfo.get(), &Size)) break; if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return false; } if (!StorageDependencyInfo->NumberEntries) return false; if(StorageType) *StorageType = StorageDependencyInfo->Version2Entries[0].VirtualStorageType; strVolumePath = StorageDependencyInfo->Version2Entries[0].HostVolumeName; strVolumePath += StorageDependencyInfo->Version2Entries[0].DependentVolumeRelativePath; // trick: ConvertNameToReal also converts \\?\{GUID} to drive letter, if possible. strVolumePath = ConvertNameToReal(strVolumePath); return true; }
string GetPathRoot(string_view const Path) { return ExtractPathRoot(ConvertNameToReal(Path)); }
void GetPathRoot(const wchar_t *Path, string &strRoot) { string RealPath; ConvertNameToReal(Path, RealPath); strRoot = ExtractPathRoot(RealPath); }
bool ScanTree::GetNextName(FAR_FIND_DATA_EX *fdata,string &strFullName) { if (!ScanItems.getCount()) return false; bool Done=false; Flags.Clear(FSCANTREE_SECONDDIRNAME); for (;;) { ScanTreeData* LastItem = ScanItems.lastItem(); if (!LastItem->Find) { LastItem->Find = new FindFile(strFindPath); } Done=!LastItem->Find->Get(*fdata); if (Flags.Check(FSCANTREE_FILESFIRST)) { if (LastItem->Flags.Check(FSCANTREE_SECONDPASS)) { if (!Done && !(fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) continue; } else { if (!Done && (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) continue; if (Done) { if(LastItem->Find) { delete LastItem->Find; LastItem->Find = nullptr; } LastItem->Flags.Set(FSCANTREE_SECONDPASS); continue; } } } break; } if (Done) { ScanItems.deleteItem(ScanItems.getCount()-1); if (!ScanItems.getCount()) return false; else { if (ScanItems.lastItem()->Flags.Check(FSCANTREE_INSIDEJUNCTION)) Flags.Clear(FSCANTREE_INSIDEJUNCTION); CutToSlash(strFindPath,true); if (Flags.Check(FSCANTREE_RETUPDIR)) { strFullName = strFindPath; apiGetFindDataEx(strFullName, *fdata); } CutToSlash(strFindPath); strFindPath += strFindMask; _SVS(SysLog(L"1. FullName='%s'",strFullName.CPtr())); if (Flags.Check(FSCANTREE_RETUPDIR)) { Flags.Set(FSCANTREE_SECONDDIRNAME); return true; } return GetNextName(fdata,strFullName); } } else { if ((fdata->dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) && Flags.Check(FSCANTREE_RECUR) && (!(fdata->dwFileAttributes&FILE_ATTRIBUTE_REPARSE_POINT) || Flags.Check(FSCANTREE_SCANSYMLINK))) { string RealPath(ScanItems.lastItem()->RealPath); AddEndSlash(RealPath); RealPath += fdata->strFileName; if (fdata->dwFileAttributes&FILE_ATTRIBUTE_REPARSE_POINT) ConvertNameToReal(RealPath, RealPath); //recursive symlinks guard bool Recursion = false; for (size_t i = 0; i < ScanItems.getCount() && !Recursion; i++) Recursion = ScanItems.getItem(i)->RealPath == RealPath; if (!Recursion) { CutToSlash(strFindPath); strFindPath += fdata->strFileName; strFullName = strFindPath; strFindPath += L"\\"; strFindPath += strFindMask; ScanItems.addItem(); ScanItems.lastItem()->Flags = ScanItems.getItem(ScanItems.getCount()-2)->Flags; // наследуем флаг ScanItems.lastItem()->Flags.Clear(FSCANTREE_SECONDPASS); ScanItems.lastItem()->RealPath = RealPath; if (fdata->dwFileAttributes&FILE_ATTRIBUTE_REPARSE_POINT) { ScanItems.lastItem()->Flags.Set(FSCANTREE_INSIDEJUNCTION); Flags.Set(FSCANTREE_INSIDEJUNCTION); } return true; } } } strFullName = strFindPath; CutToSlash(strFullName); strFullName += fdata->strFileName; return true; }
static string_view ProcessMetasymbol(string_view const CurStr, subst_data& SubstData, string& Out) { const auto append_with_escape = [EscapeAmpersands = SubstData.EscapeAmpersands](string& Destination, string_view const Str) { if (EscapeAmpersands && contains(Str, L"&"sv)) { string Escaped(Str); replace(Escaped, L"&"sv, L"&&"sv); append(Destination, Escaped); } else { append(Destination, Str); } }; if (const auto Tail = tokens::skip(CurStr, tokens::passive_panel)) { SubstData.PassivePanel = true; return Tail; } if (const auto Tail = tokens::skip(CurStr, tokens::active_panel)) { SubstData.PassivePanel = false; return Tail; } if (const auto Tail = tokens::skip(CurStr, tokens::exclamation)) { if (!starts_with(Tail, L'?')) { Out.push_back(L'!'); return Tail; } } if (const auto Tail = tokens::skip(CurStr, tokens::name_extension)) { if (!starts_with(Tail, L'?')) { append_with_escape(Out, SubstData.Default().Normal.Name); return Tail; } } if (const auto Tail = tokens::skip(CurStr, tokens::short_name)) { append_with_escape(Out, SubstData.Default().Short.NameOnly); return Tail; } const auto GetExtension = [](string_view const Name) { const auto Extension = PointToExt(Name); return Extension.empty()? Extension : Extension.substr(1); }; if (const auto Tail = tokens::skip(CurStr, tokens::short_extension)) { append_with_escape(Out, GetExtension(SubstData.Default().Short.Name)); return Tail; } if (const auto Tail = tokens::skip(CurStr, tokens::extension)) { append_with_escape(Out, GetExtension(SubstData.Default().Normal.Name)); return Tail; } const auto CollectNames = [&SubstData, &append_with_escape](string& Str, auto const Selector) { append_with_escape(Str, join(select(SubstData.Default().Panel->enum_selected(), Selector), L" "sv)); }; if (const auto Tail = tokens::skip(CurStr, tokens::short_list)) { if (!starts_with(Tail, L'?')) { CollectNames(Out, &os::fs::find_data::AlternateFileName); return Tail; } } if (const auto Tail = tokens::skip(CurStr, tokens::list)) { if (!starts_with(Tail, L'?')) { CollectNames(Out, [](const os::fs::find_data& Data) { return quote_space(Data.FileName); }); return Tail; } } const auto GetListName = [&Out, &append_with_escape](string_view const Tail, subst_data& Data, bool Short) { const auto ExclPos = Tail.find(L'!'); if (ExclPos == Tail.npos || starts_with(Tail.substr(ExclPos + 1), L'?')) return size_t{}; const auto Modifiers = Tail.substr(0, ExclPos); if (Data.ListNames) { string Str; if (Data.Default().Panel->MakeListFile(Str, Short, Modifiers)) { if (Short) Str = ConvertNameToShort(Str); append_with_escape(Out, Str); Data.ListNames->add(std::move(Str)); } } else { append(Out, L'!', Short? L'$' : L'@', Modifiers, L'!'); } return Modifiers.size() + 1; }; if (const auto Tail = tokens::skip(CurStr, tokens::list_file)) { if (const auto Offset = GetListName(Tail, SubstData, false)) return string_view(Tail).substr(Offset); } if (const auto Tail = tokens::skip(CurStr, tokens::short_list_file)) { if (const auto Offset = GetListName(Tail, SubstData, true)) return string_view(Tail).substr(Offset); } if (const auto Tail = tokens::skip(CurStr, tokens::short_name_extension)) { if (!starts_with(Tail, L'?')) { append_with_escape(Out, SubstData.Default().Short.Name); return Tail; } } if (const auto Tail = tokens::skip(CurStr, tokens::short_name_extension_safe)) { if (!starts_with(Tail, L'?')) { append_with_escape(Out, SubstData.Default().Short.Name); SubstData.PreserveLFN = true; return Tail; } } if (const auto Tail = tokens::skip(CurStr, tokens::current_drive)) { const auto CurDir = IsAbsolutePath(SubstData.This.Normal.Name)? SubstData.This.Normal.Name : SubstData.PassivePanel? SubstData.Another.Panel->GetCurDir() : SubstData.CmdDir; auto RootDir = GetPathRoot(CurDir); DeleteEndSlash(RootDir); append_with_escape(Out, RootDir); return Tail; } if (const auto Tail = tokens::skip(CurStr, tokens::description)) { Out += SubstData.Default().GetDescription(); return Tail; } const auto GetPath = [](string_view const Tail, const subst_data& Data, bool Short, bool Real) { // TODO: paths on plugin panels are ambiguous auto CurDir = Data.PassivePanel? Data.Another.Panel->GetCurDir() : Data.CmdDir; if (Real) CurDir = ConvertNameToReal(CurDir); if (Short) CurDir = ConvertNameToShort(CurDir); AddEndSlash(CurDir); return CurDir; }; if (const auto Tail = tokens::skip(CurStr, tokens::path)) { Out += GetPath(Tail, SubstData, false, false); return Tail; } if (const auto Tail = tokens::skip(CurStr, tokens::short_path)) { Out += GetPath(Tail, SubstData, true, false); return Tail; } if (const auto Tail = tokens::skip(CurStr, tokens::real_path)) { Out += GetPath(Tail, SubstData, false, true); return Tail; } if (const auto Tail = tokens::skip(CurStr, tokens::real_short_path)) { Out += GetPath(Tail, SubstData, true, true); return Tail; } // !?<title>?<init>! if (const auto Tail = tokens::skip(CurStr, tokens::input)) { auto SkipSize = SkipInputToken(CurStr); // if bad format string skip 1 char if (!SkipSize) SkipSize = 1; Out.append(CurStr.data(), SkipSize); return CurStr.substr(SkipSize); } if (const auto Tail = tokens::skip(CurStr, tokens::name)) { append(Out, PointToName(SubstData.Default().Normal.NameOnly)); return Tail; } return CurStr; }