Bug 2229529 - ntfs3: getdents64 returns incorrect d_type for symbolic links
Summary: ntfs3: getdents64 returns incorrect d_type for symbolic links
Keywords:
Status: NEW
Alias: None
Product: Fedora
Classification: Fedora
Component: kernel
Version: 38
Hardware: x86_64
OS: Linux
unspecified
low
Target Milestone: ---
Assignee: Kernel Maintainer List
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2023-08-06 19:55 UTC by Adrian Torregrosa
Modified: 2023-08-08 15:09 UTC (History)
20 users (show)

Fixed In Version:
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
Environment:
Last Closed:
Type: Bug
Embargoed:


Attachments (Terms of Use)
How I reproduce this behaviour (1.41 KB, text/plain)
2023-08-06 19:55 UTC, Adrian Torregrosa
no flags Details

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.


Note You need to log in before you can comment on or make changes to this bug.