windows - C ++ filsystem iterator ugyldigt argument

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg bruger fs::recursive\_directory\_iterator til at liste alle filer fra et drev.


Jeg passerer også fs::directory\_options::skip\_permission\_denied for at forhindre iteratoren til at kaste, når man forsøger at gå ind i ikke-tilladte mapper. Så der bør ikke være noget problem ...


Men når du forsøger at gentage inde i særlige mapper (Volume Information, Recycle.Bin, ...):


filesystem error: cannot increment recursive directory iterator: Invalid argument


Jeg skal prøve ... fange iterationen som en løsning, men hvorfor har jeg dette problem? Hvordan skal jeg rette op på dette?


Jeg kan gengive det med det minimale eksempel fra cppreference.com:


#include <fstream>
#include <iostream>
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;

int main()
{
    for(auto& p: fs::recursive\_directory\_iterator("M:", fs::directory\_options::skip\_permission\_denied))
        std::cout << p << '
';
}


Resultat:


… (Listing real files)

"M:\System Volume Information"
terminate called after throwing an instance of 'std::experimental::filesystem::v1::\_\_cxx11::filesystem\_error'
  what():  filesystem error: cannot increment recursive directory iterator: Invalid argument


EDIT: Også filsystem\_error metoderne path1 (), path2 () returnerer tomme stier. Er det en gcc bug?

Bedste reference


Hvis du simpelthen søger skip\_permission\_denied symbol i headerfiler, kan du nemt se, at dette symbol kun findes i <filesystem>, men ikke i <experimental/filesystem>. du inkluderer forkert header-fil.


og vi har brug for brug namespace fs = std::filesystem; - uden experimental sigt.


om filtilladelser - hvis opkalder har SE\_BACKUP\_PRIVILEGE: [29]



  Dette privilegium giver brugeren mulighed for at omgå filen og mappen
  tilladelser til sikkerhedskopiering af systemet. Dette privilegium får systemet til
  Giv alle læs adgangskontrol til enhver fil uanset adgangen
  kontrolliste (ACL), der er angivet for filen. Enhver anmodning om adgang til andre
  end læses evalueres stadig med ACL. Følgende adgangsrettigheder
  gives, hvis dette privilegium holdes:

  
  

      
  • READ\_CONTROL

  •   
  • ACCESS\_SYSTEM\_SECURITY

  •   
  • FILE\_GENERIC\_READ

  •   
  • FILE\_TRAVERSE

  •   

  
  Brugertilstandsprogrammer repræsenterer dette privilegium som følgende
  bruger-højre streng: 'Sikkerhedskopiere filer og mapper'.



vi skal også bruge FILE\_OPEN\_FOR\_BACKUP\_INTENT i NtCreateFile eller NtOpenFile opkald. eller FILE\_FLAG\_BACKUP\_SEMANTICS i CreateFile. [30] [31] [32]


Når vi bruger recursive\_directory\_iterator, kontrollerer vi ikke dette punkt (ikke direkte åben mappe selv). men i den nuværende implementering fungerer dette klassesamtale FindFirstFileExW for iterat. dette api interne opkald NtOpenFile altid med FILE\_OPEN\_FOR\_BACKUP\_INTENT mulighed. som resultat SeBackupPrivilege arbejder her. vi skal aktivere SE\_BACKUP\_PRIVILEGE i tråd eller procestoken, selvfølgelig, hvis vi har dette privilegium i token: [33]


#define LAA(se) {{se},SE\_PRIVILEGE\_ENABLED|SE\_PRIVILEGE\_ENABLED\_BY\_DEFAULT}

#define BEGIN\_PRIVILEGES(tp, n) static const struct {ULONG PrivilegeCount;LUID\_AND\_ATTRIBUTES Privileges[n];} tp = {n,{
#define END\_PRIVILEGES }};

// in case you not include wdm.h, where this defined
#define SE\_BACKUP\_PRIVILEGE (17L)

ULONG AdjustPrivileges()
{
    if (ImpersonateSelf(SecurityImpersonation))
    {
        HANDLE hToken;
        if (OpenThreadToken(GetCurrentThread(), TOKEN\_ADJUST\_PRIVILEGES, TRUE, &hToken))
        {
            BEGIN\_PRIVILEGES(tp, 1)
                LAA(SE\_BACKUP\_PRIVILEGE),
            END\_PRIVILEGES
            AdjustTokenPrivileges(hToken, FALSE, (PTOKEN\_PRIVILEGES)&tp, 0, 0, 0);
            CloseHandle(hToken);
        }
    }

    return GetLastError();
}


Endelig kode kan se ud:


#include <filesystem>

void demo()
{
    AdjustPrivileges();

    fs::recursive\_directory\_iterator item(L"c:\System Volume Information", 
        fs::directory\_options::skip\_permission\_denied), end;

    while (item != end)
    {
        DbgPrint("\%S
", item->path().c\_str());
        item++;
    }
}