5

I am running os.walk() on "C:\Users\confusedDev\Documents", I see ["My Music", "My Pictures"...] returned as subDirs but they are not actually being visited. After some research I found that they are actually junctions in Windows.

My understanding is that junction is a symlink points to directory, which gets ignored by default during os.walk(), but the following test has failed me

>>> os.path.islink("C:\\Users\\confusedDev\\Documents\\My Pictures")
False

hmm...how did os.walk() know that "C:\Users\confusedDev\Documents\My Pictures" is a symlink to "C:\Users\confusedDev\Pictures" and needed to be skipped? I want to call the same api...For now, my workaround logic simply assumes that if a directory is skipped by os.walk(), it is a junction

watashiSHUN
  • 9,684
  • 4
  • 36
  • 44
  • Possible duplicate of [os.path.islink on windows with python](https://stackoverflow.com/questions/15258506/os-path-islink-on-windows-with-python) – Grzegorz Oledzki Nov 24 '17 at 09:17
  • The implementation of `os.[l]stat` is internally inconsistent. For `follow_symlinks` it handles any reparse point as a link, instead of correctly limiting this to just symlinks and [some] junctions. Additionally, when creating the stat result, it accepts only symlink reparse points for the `S_IFLNK` mode flag, which is what `islink` checks. It should also accept junctions, but only when they implement a legacy link, i.e. *not* when the target is a "\\?\Volume{...}" mountpoint for which `GetVolumeNameForVolumeMountPoint` would succeed. – Eryk Sun Nov 24 '17 at 11:40
  • 1
    @GrzegorzOledzki, he is talking about Windows `junction links`, not symbolic links: https://stackoverflow.com/questions/9042542/what-is-the-difference-between-ntfs-junction-points-and-symbolic-links. they are not the same in windows.. and `islink` returns false even in Python3 for `junction links`. Any idea how to check `junction links` in python? – alpha_989 Mar 26 '18 at 16:41

3 Answers3

9

A bit late, but you can wrap os.readlink() in a try and except for directory junctions, and then put that in a function you could call, like this:

def is_junction(path: str) -> bool:
    try:
        return bool(os.readlink(path))
    except OSError:
        return False
Demez
  • 91
  • 1
  • 2
3

Another way that I'm going to use is subprocess. Just calling the external windows program that gives info about links in Windows, return you a 0 as return code if link exists, and other if doesn't exists or is not a link:

fsutil reparsepoint query "<PathToTest>"

Something like this for example:

src = "C:\\Windows"
child = subprocess.Popen(
    "fsutil reparsepoint query \"{}\"".format(src),
    stdout=subprocess.PIPE
)
streamdata = child.communicate()[0]
rc = child.returncode

if rc == 0:
    print("Link exists")

On Windows 10 works fine as a normal user (also create links), but for Windows 7 you needs Admin Rights. For me is not a problem, because my application will check the link to create a new one, so it needs Admin Rights on Windows 7 anyway.

Greetings!

  • Thank god, you are the only, only, only one totally correct without using win32 library or ctypes which is not reliable. Thank you very much . I 've been using "dir" for a while. And finally I get your decent solution. – Alen Wesker Apr 02 '20 at 08:38
1

Using python3.5, islink returns false for junction links. It seems python3.5 doesnt natively support junction links, but support for junction links can be added using ctypes or external libraries:

  1. Using external module for ntfs: https://github.com/Juntalis/ntfslink-python/tree/master/ntfslink

  2. Using win32 module in pywin32: http://docs.activestate.com/activepython/2.5/pywin32/win32file__CreateSymbolicLink_meth.html

  3. directly calling dlls: https://stackoverflow.com/a/1143276/4752883

These are more involved solutions. Further, if you use junction links, they wont work on previous versions of windows or on other OSes.

TL;DR To make it portable, it may be better to instead convert your junction links to symbolic links using mklink /D instead of mklink /J. symbolic links are recognized by os.walk and os.path.islink.

alpha_989
  • 4,882
  • 2
  • 37
  • 48