#1008507 libc6: pathconf("mountpont of FAT filesystem", _PC_LINK_MAX) returns 127, expected 1

Package:
libc6
Source:
glibc
Description:
GNU C Library: Shared libraries
Submitter:
Joshua
Date:
2022-11-30 18:21:07 UTC
Severity:
normal
Tags:
#1008507#5
Date:
2022-03-28 04:19:00 UTC
From:
To:
Dear Maintainer,

what lead up to the situation is well-described in my stackoverflow post:
https://stackoverflow.com/questions/71641957/how-to-check-if-a-filesystem-supports-hard-links-in-linux

Since posting it, I have traced the bug through the glibc sources and found that it's bugged.
There's cases for common filesystems that have nonstandard values, but you almost never care
what the actual value is.

On the other hand, there are no cases for writable filesystems that simply don't have hard links.
(FAT). EXFAT would also fall into this but that only exists as a FUSE module right now.

These turn out to be the ones we care about becasue they are three of the four widely supported
filesystems on removable media (with the fourth being UDF).

Writing a patch is trivial. Getting it into glibc, well I'm gonna try but you may have more luck.

#1008507#10
Date:
2022-03-30 00:47:40 UTC
From:
To:
/* reproduce glibc bug */

/*
 * I don't typically care what the return of pathconf(..., _PC_LINK_MAX)
 * is; I just care whether or not it's greater than 1 because I'm checking
 * whether the filesystem supports hard links or not.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

int main()
{
    char file[40];
    char dir[40];
    char commandbuf[120];
    sprintf(file, "/tmp/%u.img", getpid());
    sprintf(dir, "/tmp/%u.mnt", getpid());
    FILE *fimage = fopen(file, "wb");
    fseek(fimage, 1440 * 1024 - 1, SEEK_SET);
    fputc(0, fimage);
    fclose(fimage);
    mkdir(dir, 0);
    sprintf(commandbuf, "mkfs.fat /tmp/%u.img", getpid());
    if (system(commandbuf) != 0) {
        rmdir(dir);
        unlink(file);
        return 1;
    }

    sprintf(commandbuf, "mount -o loop -t msdos %s %s", file, dir);
    if (system(commandbuf) != 0) {
        rmdir(dir);
        unlink(file);
        return 1;
    }

    int r;
    printf("Testing pathconf(%s, _PC_LINK_MAX)...");
    r = pathconf(dir, _PC_LINK_MAX) != 1;
    printf(r ? "Failed\n" : "OK\n");
    sprintf(commandbuf, "umount %s", dir);
    system(commandbuf);
    rmdir(dir);
    unlink(file);
    return r;
}

#1008507#15
Date:
2022-03-30 00:53:41 UTC
From:
To:
diff -ur glibc.orig/glibc/sysdeps/unix/sysv/linux/pathconf.c
glibc/glibc/sysdeps/unix/sysv/linux/pathconf.c
--- glibc.orig/glibc/sysdeps/unix/sysv/linux/pathconf.c    2022-03-29
17:50:12.558027042 -0700
+++ glibc/glibc/sysdeps/unix/sysv/linux/pathconf.c    2022-03-29
17:52:33.262157543 -0700
@@ -183,6 +183,11 @@
     case XFS_SUPER_MAGIC:
       return XFS_LINK_MAX;

+    case MSDOS_SUPER_MAGIC:
+#ifdef EXFAT_SUPER_MAGIC // For when it gets added in about 30 years
+    case EXFAT_SUPER_MAGIC:
+#endif
+      return 1;
     case LUSTRE_SUPER_MAGIC:
       return LUSTRE_LINK_MAX;

#1008507#20
Date:
2022-04-05 21:34:25 UTC
From:
To:
Hi,

If you ended with a patch, the best is probably to submit it upstream to
libc-alpha@sourceware.org .

Regards
Aurelien