Also....
Das Magic für exfat ist (//edit2: zu finden in /usr/include/linux/magic.h, braucht nicht extra includet werden!), wo sich auch dein MSDOS_SUPER_MAGIC findet
...
#define MSDOS_SUPER_MAGIC 0x4d44 /* MD */
#define EXFAT_SUPER_MAGIC 0x2011BAB0
...
(man pages können halt auch veraltet sein), gut das es grep gibt<g>
Das wäre die gewünschte "einfache Antwort", wenn da nicht das Wort wenn wäre...
Du kannst das austesten, aber es wird ggf. nicht funktionieren wie es z.B. bei deinen fat/vfat funktioniert. ¹
Weil, und da bin ich die ganze Zeit hängen geblieben da ich von exfat kaum was weiß...
Es gibt zwei mögliche Wege, ein exfat als Dateisystem zu verwenden:
a) einmal über libfuse (FUSE, Filesystem in USErspace)
b) ab Kernel 5.4 (ca. 2013) aber auch als Kernel-Modul
Ich habe bei kurzem Suchen vorher schon paarmal gelesen, daß es eben auch ein Modul direkt im Kernel gibt, und mich gewundert daß das nicht geladen wird. Aber nicht weitergebohrt.
Situation unter Archlinux:
$ pacman -Ss exfat
extra/exfat-utils 1.4.0-4
Utilities for exFAT file system
extra/exfatprogs 1.3.0-1 [Installiert]
exFAT filesystem userspace utilities for the Linux Kernel exfat driver
Wenn das Paket exfat-utils installiert ist, dann wird ein exfat FS mittels FUSE von mount eingehängt. Das war bei mir, meinen Tests bisher so.
Das führt eben zur "Problematik", daß statfs SystemCalls exfat "nur" als fuse/fuseblk identifizieren kann(dürfte dann wie im letzten Post aufgeführt FUSE_SUPER_MAGIC 0x65735546 sein. Unter diesem Magic können sich nun aber sehr viele (Usespace)-Dateisysteme "tummeln", und statfs hat keine Möglichkeit diese weitergehend zu identifizieren. Es gibt sogar eine ext2/3/4 FUSE Implementation, nebst z.B. dem prominenten ntfs-3g.
Diesem Problem versuchte ich in meinem oneliner-Ansatz eben durch eine (zweite) Erkennung über die raw-Partition beileibe zu rücken.
Wenn hingegen das Paket exfatprogs verwendet wird (steht in Konflikt mit exfat-utils), dann wird ein exfat-FS mittels des Kernel-Moduls(exfat) gemountet.
Und dann funktioniert auch stat / statfs-calls (und obiges Magic).
Zum Test/Beleg:
mit installiertem exfatprogs (direkt im Kernel)
# mount --mkdir /dev/loop0 /mnt/test
# mount |grep test
/dev/loop0 on /mnt/test type exfat (rw,relatime,fmask=0022,dmask=0022,iocharset=utf8,errors=remount-ro)
# stat --format=%T --file-system /mnt/test/testfile
exfat
# findmnt --output SOURCE,FSTYPE,ID --target /mnt/test/testfile
SOURCE FSTYPE ID
/dev/loop0 exfat 389
Es wird (mittels statfs) also überall korrekt exfat angezeigt/identifiziert
Hingegen wenn ich (wieder) exfat-utils insatlliere (also mittels FUSE) wird als "Kennung" wieder nur luse/fuseblk gezeigt
# umount /mnt/test
# pacman -S exfat-utils (ersetzt das exfatprogs)
# mount --mkdir /dev/loop0 /mnt/test
FUSE exfat 1.4.0 (libfuse3) <--- Da steht es! //Edit: Ich dachte halt das wäre die einzige Möglichkeit für exfat
# mount |grep test
/dev/loop0 on /mnt/test type fuseblk (rw,nosuid,nodev,relatime,user_id=0,group_id=0,default_permissions,allow_other,blksize=4096)
# stat --format=%T --file-system /mnt/test/testfile
fuse
# findmnt --output SOURCE,FSTYPE,ID --target /mnt/test/testfile
SOURCE FSTYPE ID
/dev/loop0 fuseblk 389
tl;dr: Sicherstellen, daß für exfat das Paket exfatprogs installiert ist/wird. Auch für Dinge wie Performance ist ein nativer Kernel-Zugriff immer besser als eine "Zwischenschicht" über etwas wie FUSE.
Auch für automatische Mounts wird dann die Methode über das Kernel-Modul verwendet.
Für dein Programm stellt sich halt die Frage, wie du sicherstellen kannst (wenn überhaupt) daß die Anwender eben keine FUSE-basierte Methode verwenden. Du kannst das ggf. über "Kommunikation" oder Abhängigkeits-Voraussetzung zu der Lösung ohne FUSE machen.
¹ //Edit3: Teste mit obigem Magic ruhig mal beide exfat-Möglichkeiten aus ob das Magic "greift". Evtl. bezieht sich das Problem ja nur auf die Ausgabe via stat/findmnt (fuse/fuseblk), dein statfs SysCall im Programm funktioniert aber ggf. bei beiden Ansätzen. Mount muß ja die zu mountende Partition auch "analysieren" um automatisch das Dateisystem zu erkennen und (irgendeinen) passenden Dateisystem-"Treiber" zu verwenden.
//Edit4: Ich hab mal getestet, es funktioniert mit statfs nur mit der Kernel-Modul-Methode:
Mein Code:
#include <stdio.h>
#include <sys/statfs.h>
#include <linux/magic.h>
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "Usage: %s <path>\n", argv[0]);
return 1;
}
printf("Testing file: %s\n", argv[1]);
struct statfs fs_data;
if ( statfs(argv[1], &fs_data) == 0) {
if (fs_data.f_type == BTRFS_SUPER_MAGIC)
printf("FS is BTRFS (%#x)\n", fs_data.f_type);
else if (fs_data.f_type == EXFAT_SUPER_MAGIC)
printf("FS is exfat (%#x)\n", fs_data.f_type);
else
printf("FS not matched (%#x)\n", fs_data.f_type);
} else {
perror("statfs");
return 1;
}
return 0;
}
Ohne FUSE(exfatprogs):
$ ./a.out ./test.c
Testing file: ./test.c
FS is BTRFS (0x9123683e)
$ ./a.out /mnt/test/testfile
Testing file: /mnt/test/testfile
FS is exfat (0x2011bab0)
Mit FUSE(exfat-utils):
$ ./a.out /mnt/test/testfile
Testing file: /mnt/test/testfile
FS not matched (0x65735546)
Und 0x65735546 ist halt FUSE_SUPER_MAGIC, was halt leider jedes Dateisystem sein kann welches per libfuse eingebunden ist :-(
Für dieses Magic müßte man halt doch wieder auf eine Zusatzprüfung zurückgreifen, welche das FS anhand der Partitions-Metadaten prüft eben für die Partition/Blockdevice auf der die untersuchende Datei liegt. Mir ist das zuviel "C", kann ich leider nicht weiterhelfen. Bin ein altes Shellscript oder Interpreter-Sprachen(Ruby ftw!) Hackerlein <g> (Der obige Code war schon Quälerei für mich...)