Reproducible example for this issue with os.walk
not detecting symlinks correctly on mounted CIFS filesystems due to a bug in the kernel CIFS driver.
- Install samba (
sudo apt install samba
) - Fill out
smb.conf
with the needed values and place at/etc/samba/smb.conf
- Restart samba to pick up new config (
sudo systemctl restart smbd.service
) - Mount the share somewhere (
sudo mount -f cifs -o guest,vers=3.0,uid=1000,gid=1000,mfsymlinks //127.0.0.1/symlinks /mnt/cifs
) - Run
mklinks.sh
to create some symbolic links from the client (mklinks.sh /mnt/cifs
)- This will make some links in
results
that point to../source
- This will make some links in
- Compile the C program to show the discrepency between the system calls (
gcc -o testdent testdent.c
) - Run the C program and point it to the CIFS mount point results folder:
./testdent /mnt/cifs/results
- The output should look like the following:
linked
D_TYPE=Regular file
LSTAT type=Link
STAT type=Directory
link.txt
D_TYPE=Regular file
LSTAT type=Link
STAT type=Regular file
Where the D_TYPE
value is incorrectly reported for both symlinks
-
os.walk
usesscandir
which usesreaddir
system call-
Relies on
d_type
property of struct returned byreaddir
to determine if file, dir, link, etc -
Done to avoid making extra
stat
system call for each item -
If
DT_UNKOWN
, falls back tostat
-
d_type
incorrectly reported asDT_REG
with CIFS instead ofDT_DIR/DT_LNK
orDT_UNKNOWN
-
-
pathlib
usesos.path.is_
which usesstat
system call -
CIFS does not natively support symlinks
-
Can emulate symlinks using
mfsymlinks
mount option in order to create symlinks from the client -
Existing symlinks not created by client are presented as hardlinks and do not have the above issue with the wrong
d_type
value
-
-
Use NFS if possible (full POSIX compliance)
-
Use alternative traversal methods (i.e.
pathlib
)- Less efficient (extra
stat
system call for each item to determine if file or folder)
- Less efficient (extra