Bug 2229529

Summary: ntfs3: getdents64 returns incorrect d_type for symbolic links
Product: [Fedora] Fedora Reporter: Adrian Torregrosa <adrian.torregrosa>
Component: kernelAssignee: Kernel Maintainer List <kernel-maint>
Status: NEW --- QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: low Docs Contact:
Priority: unspecified    
Version: 38CC: acaringi, adscvr, airlied, alciregi, bskeggs, hdegoede, hpa, jarod, josef, kdudka, kernel-maint, lgoncalv, linville, lzaoral, masami256, mchehab, ptalbert, steved, svashisht, vcrhonek
Target Milestone: ---   
Target Release: ---   
Hardware: x86_64   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Attachments:
Description Flags
How I reproduce this behaviour none

Description Adrian Torregrosa 2023-08-06 19:55:18 UTC
Created attachment 1982003 [details]
How I reproduce this behaviour

Description of problem:
Apparently find does not find soft links when these are on an NTFS device

Version-Release number of selected component (if applicable):
findutils-4.9.0-3.fc38.x86_64

How reproducible:
Always

Steps to Reproduce:
1. Connect an NTFS-formatted device to your Fedora Workstation
2. In the directory where the OS mounts the NTFS device, create a file and a soft-link to that file
3. Give a command such as "find <that_directory> -type l"

Actual results:
The find command does not find the soft-link.

Expected results:
The find command should find the soft-link.

Additional info:
The find command does find soft-links under other formats such as EXT4.
The find command does find the soft-link in the NTFS device if it looks for regular files.

Comment 1 Lukáš Zaoral 2023-08-08 15:07:35 UTC
Hello!
I was able to reproduce this issue on my machine.  Unfortunately, this seems to be a bug in the kernel.  find internally uses the fts* functions from glibc to traverse the filesystem and it tries to minimise the number of (l)stat(2) calls by reusing as much information it already has acquired before.  For fts to work, glibc internally calls readdir(3) which is implemented using the getdents64(2) syscall.  The structure forwarded by readdir(3) from getdents64(2) for every directory entry also contains file type information which seems to be incorrect for symlinks on NTFS volumes as witnessed by the following experiment:

$mount
...
/dev/sda1 on /mnt/ntfs type ntfs3 (rw,relatime,uid=0,gid=0,iocharset=utf8)
$ cat ~/tmp/readdir_test.c
#include <dirent.h>
#include <stdio.h>
#include <sys/types.h>

int main(int argc, char* argv[])
{
    DIR* dp = opendir(argv[1]);
    if (dp == NULL) {
        perror("opendir");
        return 1;
    }

    struct dirent* dent;
    while ((dent = readdir(dp)) != NULL) {
        const char* type;
        switch (dent->d_type) {
            case DT_BLK:
                type = "block dev"; break;
            case DT_CHR:
                type = "char dev"; break;
            case DT_DIR:
                type = "dir"; break;
            case DT_FIFO:
                type = "pipe"; break;
            case DT_LNK:
                type = "symlink"; break;
            case DT_REG:
                type = "regular file"; break;
            case DT_SOCK:
                type = "socket"; break;
            case DT_UNKNOWN:
                type = "unknown"; break;
        }
        printf("name: %s, type: %s\n", dent->d_name, type);
    }

    closedir(dp);
}
$ cc ~/tmp/readdir_test.c
$ ./a.out /mnt/ntfs
name: ., type: dir
name: .., type: dir
name: a, type: regular file
name: b, type: regular file  <-- WRONG!


I've checked ls and while it also uses readdir(3), it always issues an explicit (l)stat(2) so that's the reason why the final displayed information are correct.

Comment 2 Lukáš Zaoral 2023-08-08 15:09:58 UTC
I forgot to mention that I've used the enclosed reproducer for the experiment above.