Open sdawson-nvidia opened 1 year ago
@serhiy-storchaka (as an os.path module expert)
The "mfsymlinks" option of the Linux "cifs" filesystem emulates native POSIX symlinks on an SMB share. When lstat()
is called on an emulated symlink, the stat result does have the correct S_IFLNK
file type. However, the file type in the readdir()
entry of an emulated symlink is DT_REG
(regular file) instead of DT_LNK
. That's a third-party bug that needs to be handled by the developers of the "cifs" filesystem driver.
I compiled a "listdir" program that calls opendir()
and readdir()
to list the name and type of each entry in a directory. Here's the result for an SMB share mounted in Linux with "mfsymlinks". The share contains a directory, a file, and an emulated symlink to each.
$ ./listdir /mnt/temp/linktest
dir: DT_DIR
dirlink: DT_REG
file: DT_REG
filelink: DT_REG
As you can see, the links are misreported as type DT_REG
. It's apparent why emulated symlinks are reported as regular files in the low-level directory listing, because that's what they really are when accessed from Windows:
>>> open('dirlink', 'rb').read(47)
b'XSym\n0003\n736007832d2167baaae763fd3a3f3cf1\ndir\n'
>>> open('filelink', 'rb').read(48)
b'XSym\n0004\n8c7dd922ad47494fc02c388e12c00eac\nfile\n'
The developers forgot to maintain the pretense for readdir()
. The GNU "ls" command happens to show these entries correctly as links, but that's only after calling lstat()
on each entry, which I confirmed using "strace".
os.scandir()
is designed to rely on the d_type
of the directory entry if it's not DT_UNKNOWN
. Having to call lstat()
would defeat the purpose of using os.scandir()
.
Thank you for the investigation @eryksun. I've sent an email to linux-cifs@vger.kernel.org to follow up on this issue.
We just ran into this as well. Looks like the thread on the mailing list died. Though, even if it did get patched it would take a long time to trickle into distributions.
Bug report
With a network drive mounted with CIFS and using the mfsymlinks options, os.path.islink and os.path.isdir will return True for a symbolic link to a directory, whereas the corresponding DirEntry for the symlink will return False for both DirEntry.is_symlink() and DirEntry.is_dir().
Repro steps:
Your environment
Python version 3.8.10, Ubuntu 20.04