Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-69001

QDirIterator, QDir::entry[Info]List() do not skip Windows symlinks; fileInfo.isSymLink() == false

    XMLWordPrintable

Details

    • Bug
    • Resolution: Unresolved
    • P3: Somewhat important
    • None
    • 5.7.1, 5.10.1
    • Core: I/O
    • None
    • Win7SP1, tested with MSVC2015 and MinGW 5.3.0 (the version installed by Qt).
    • Windows

    Description

      When using QDir::NoSymLinks and/or excluding QDirIterator::FollowSymLinks, links on Windows (made with mklink) are not skipped.  Also QDirIterator::fileInfo.isSymLink() returns false on these entries.

      This is rather awkward, because one might expect the relevant QDir and QDirIterator flags to work on them, but they don't.

      As a result, one can't use things like QDir::entryList() or QDirIterator directly if one wishes to exclude Windows symlinks. The links have to be excluded "manually" using a custom WinAPI-based function. Trying to filter out anything behind a linked folder with QDirIterator is especially awkward since it will still iterate into linked folders (can't see how to prevent that), and the actual files inside those folders are not links.... so one has to somehow ignore all those files (keep a list of ignored folders, or whatever).

      They're true links after all, with a target, just like on *nix, so why are they treated differently? I understand it is an "advanced" feature to create such links in Windows, but this is not uncommon at all (there are even GUI apps to do this).

      The following abbreviated example returns true for file links (mklink Link Target) and directory links/junctions (mklink (/D|/J) Link Target). Only file "hard links" are not detected (mklink /H). (I'm not sure the latter can be detected since they don't even show as links in native DIR listing (the other types all do). Note that one cannot create a "hard link" to a folder (mklink /D /H).)

      #include <qplatformdefs.h>
      #include <qt_windows.h>
      bool SyncProcess::isWindowsSymlink(const QString &filename) {
         WIN32_FIND_DATAW
      findData;
         FindFirstFileExW((const wchar_t *)filename.utf16(), FindExInfoBasic, &findData, FindExSearchNameMatch, NULL, 0);
         return (
      findData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
           
      (findData.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT  // Junction
            || findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK);        // file/folder symlink
      }

      Test script:

      QDirIterator it("c:/test", QDir::Dirs | QDir::Files | QDir::NoSymLinks, QDirIterator::Subdirectories);
      while
      (it.hasNext()) {
        it
      .next();
        const
      QFileInfo fi = it.fileInfo();
        if (fi.isSymLink()) {   // always false on Windows, except for .lnk (shortcut) files.
          qDebug() << "Is symlink" << fi.absoluteFilePath() << fi.canonicalFilePath() << fi.symLinkTarget(); }
       else if
      (isWindowsSymlink(fi.absoluteFilePath())) {  // true for symlinks and junctions
         qDebug() << "Windows symlink" << fi.absoluteFilePath() << fi.canonicalFilePath() << fi.symLinkTarget(); }
      }

      QFileInfo::canonicalPath() returns the correct target location for the 3 types of links mentioned (file and folder symlinks, and Junctions).  QFileInfo::symLinkTarget() is blank though.

      I do see in qfilesystemmetadata_p.h that it already checks for IO_REPARSE_TAG_SYMLINK, but I have no idea why even that part wouldn't be working (or if this code is even relevant to the subject).

      For reference:

      MKLINK [[/D] | [/H] | [/J]] Link Target
      
      /D Creates a directory symbolic link. Default is a file symbolic link.
      /H Creates a hard link instead of a symbolic link.
      /J Creates a Directory Junction.
      Link specifies the new symbolic link name.
      Target specifies the path (relative or absolute) that the new link refers to.
      

       
      Possibly related: QTBUG-45344
       
       
       
       
       
       
       

      Attachments

        Issue Links

          Activity

            People

              thiago Thiago Macieira
              mpaperno Maxim Paperno
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated: