How to tell if a directory is a windows junction in python
Asked Answered
A

5

6

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

Antithesis answered 24/11, 2017 at 9:12 Comment(3)
Possible duplicate of os.path.islink on windows with pythonPhotogene
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.Rosen
@GrzegorzOledzki, he is talking about Windows junction links, not symbolic links: #9043042. 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?Dissimulation
B
10

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
Bear answered 24/1, 2020 at 23:18 Comment(0)
E
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!

Exhibit answered 13/2, 2019 at 19:55 Comment(1)
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.Frogman
D
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://mcmap.net/q/375016/-create-ntfs-junction-point-in-python

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.

Dissimulation answered 26/3, 2018 at 16:50 Comment(0)
I
0

You can use os.path.isjunction(path) to check if the path is a directory junction.

needs at least python 3.12

https://docs.python.org/3/library/os.path.html#os.path.isjunction

Improbable answered 27/11, 2023 at 13:19 Comment(0)
G
0

if you just need to know if it is linked, you can use pathlib.Path().resolve() like:

path = Path('somedir')
if path.absolute() != path.resolve():
    print(f'{path} is a link to {path.resolve()}')

if you then check is_symlink() to exclude symlinks, you're left with junctions or hardlinks.

haven't figured out a good way to exclude hardlinks, but for all of my use-cases, knowing if it was a link, was sufficient.

Grotto answered 19/3 at 9:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.