0

On my Windows 11 laptop with Python 3.12.9, I am getting an unexpected result using os.scandir and os.stat on a windows shortcut.
I would like to find out if the [os.scandir, os.listdir, os.stat, et al] entry is a symlink (aka shortcut) without resorting to comparing the file extension (e.g. os.path.splitext(entry)[1] == ".lnk")

I have the following test folder structure on my local C:\:

\test\
   pic.jpg
   pic.jpg - Shortcut.lnk
   dir\

That is one picture file, a shortcut (sym link) to the picture file, and sub folder.

using this test code:

import os
import stat

p = r"C:\test"
fs = False
print("follow_symlinks=",fs)
for e in os.scandir(p):
    s = os.stat(e.path,follow_symlinks=fs)
    m = s.st_mode
    print(e.name, "win",s.st_file_attributes, "mode",m)
    print("   file",e.is_file(follow_symlinks=fs),", dir",e.is_dir(follow_symlinks=fs))
    print("   sym",e.is_symlink(),",junct",e.is_junction())
    print("   ssym",stat.S_ISLNK(m),",sfile",stat.S_ISREG(m),",sdir",stat.S_ISDIR(m))

gives the following output:

follow_symlinks= False
dir win 16 mode 16895
   file False , dir True
   sym False ,junct False
   ssym False ,sfile False ,sdir True
pic.jpg win 32 mode 33206
   file True , dir False
   sym False ,junct False
   ssym False ,sfile True ,sdir False
pic.jpg - Shortcut.lnk win 32 mode 33206
   file True , dir False
   sym False ,junct False
   ssym False ,sfile True ,sdir False

Setting fs (follow_symlinks) to True shows the exact same output.

Since I am not following symlinks I expected the results for "pic.jpg - Shortcut.lnk" to be
file False, sym True, junct True, ssym True sfile False
Is the test code correct to determine if the entry is a symlink?

I use the reference file modes from https://docs.python.org/3/library/stat.html#module-stat and windows file attributes from https://learn.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants?redirectedfrom=MSDN


mode 16895 is mode 16384 (directory) plus permissions
mode 33206 is mode 32768 (regular file) plus permissions
windows attribute 16 is FILE_ATTRIBUTE_DIRECTORY
windows attribute 32 is FILE_ATTRIBUTE_ARCHIVE, bitwise & 2,4 or 128 are also acceptable

Any clarification or help would be appreciated.

4
  • 1
    Welcome to Stack Overflow! I believe the reason you see this behavior is simply because windows shortcuts are not symlinks. They're just a different kind of thing. True symlinks are also possible on Windows, and your method would presumably detect those. Commented Apr 9 at 21:10
  • 2
    A .lnk file is not a symlink on Windows. It just a "shortcut" recognized by Explorer. Use os.symlink (in administrator mode, typically) to create a symlink on Windows. Commented Apr 9 at 21:10
  • As for how to detect shortcuts, it looks like the pywin32 library may be able to do that. Commented Apr 9 at 21:10
  • See Also: How can I create a symbolic link on Windows 10? Commented Apr 9 at 22:23

1 Answer 1

0

I have reviewed the information suggested by @Brendan Mitchell, @Mark Tolonen and @JonSG, thank you.

I would like to accept their comments as an answer because a Windows shortcut created by windows explorer is a special file, not a symlink or a junction.

That means that os.scandir [os.listdir, et al] will not follow the *.lnk file, even if the parameter "follow_symlinks=True". I also cannot find any windows stat().st_file_attribute that would indicate that the file is a shortcut.

So the only way to determine a shortcut is by comparing the file extension:

if os.path.splitext(filename)[1] == ".lnk"

or

if filename[-4:] == ".lnk"

Determining the target of a shortcut has been discussed elsewhere.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.