vdrnfofs mit Python 3

  • Was mich wundert, daß nach dem mount (vdrnfofs ....) ein "df" kein fuse- oder sonstwie gemountetes Verzeichnis zeigt.

  • ASCII-Zeichen und Quotes in Dateinamen sollten eigentlich kein Problem machen, bei Unicode muss man ggf. aufpassen (das kann ich aus dem Code nicht abschätzen, ob es da ein Problem geben kann, weil ich das fuse-Modul nicht besonders gut kenne) - kannst du mal bitte eine vollständige Ausgabe des Verzeichnis-Inhalts anhängen, dann kann ich mal versuchen das nachzustellen. Asterix_+_Obelix_-_Im_Auftrag_Ihrer_Majestät_-_Astérix_et_Obélix_Au_service_de_Sa_Majesté wäre z.B. eine Aufnahme, die Unicode-Zeichen im Pfad hat.


    Du könntest auch mal versuchen pydb anzuwerfen, eventuell sieht man damit mehr:

    python3 -m pdb $(which vdrnfofs) /mnt/vdrnfofs -d -o video=/srv/vdr/video,allow_other -o loglevel=debug

    Wenn der pdb-Prompt angezeigt wird, das Skript mit c (gefolgt von der Eingabetaste) laufen lassen und dann versuchen den Crash zu provozieren.

    yaVDR-Dokumentation (Ceterum censeo enchiridia esse lectitanda.)

  • Nochmal danke für Deine Arbeit!

    Im Anhang das Listing mit default (de_AT.UTF8) und auch mit LANG=C


    Mit pydb sieht es auch nicht viel anders aus:

  • Also eine wilde Mischung von Encodings in den Verzeichnisnamen - mit deiner Liste an Verzeichnisnamen kann ich den Crash schon mal reproduzieren, jetzt muss ich nur noch herausfinden, wo genau und warum es knallt...


    Edit: es knallt laut gdb in der libfuse.so.2, also geht da vermutlich bei der Übergabe des Dateinamens an die Bibliothek etwas schief.

    yaVDR-Dokumentation (Ceterum censeo enchiridia esse lectitanda.)

    Einmal editiert, zuletzt von seahawk1986 ()

  • Das sieht für mich nach einem Fehler im C-Code in den Python-Bindings für die libfuse aus (https://github.com/libfuse/pyt…eparts/_fusemodule.c#L401 ff. (wobei PyString_AsString per Macro zu PyUnicode_AsUTF8 wird, wenn für Python3 kompiliert wird) - die nutzen also PyUnicode_AsUTF8 statt dem - wenn ich das richtig verstehe - dafür unter Python >= 3.2 vorgesehenen mit PyUnicode_EncodeFSDefault, das ein PyBytesObject zurückgibt, dessen Inhalt man dann mittels PyBytes_AsString als char* bekommt. Da PyUnicode_AsUTF8 immer mit 'strict' statt mit konvertiert, liefert die Funktion bei nicht UTF-8 konformen Zeichen einen leeren String zurück, was in keinem Fall ein gültiger Dateiname ist.


    Vielleicht mag jemand den Patch ausprobieren:

    Wer Ubuntu 20.04 nutzt, kann mal probieren die angehängte Datei zu entpacken und mit der darin enthaltenen Shared Library die vorhandene /usr/lib/python3/dist-packages/fuseparts/_fuse.cpython-38-x86_64-linux-gnu.so zu ersetzen.


    Das Escaping in der Shell sieht dann nicht besonders schön aus, aber er crasht nicht mehr (daher würde ich mir überlegen, ob man Dateinamen mit kaputtem Encoding in vdrnfofs aufräumt oder mit (c)chardet versucht das korrekte Encoding zu erkennen und dann einen "hübschen" Pfad präsentiert - das geht dann natürlich zu Lasten der Performance):

    'Mord_im_Spiegel_-_The_Mirror_Crack--'$'\231''d_2020-01-04.20.15.1-0.rec.mpg'


    Edit: und leider kann man auf die Datei auch nicht zugreifen, weil der Pfad nicht korrekt aufgelöst wird.

    Dateien

    yaVDR-Dokumentation (Ceterum censeo enchiridia esse lectitanda.)

    Einmal editiert, zuletzt von seahawk1986 ()

  • Interessant. Erstmal danke für die ausführliche Analyse des Problems. Bekommst du das hin das eines der einfachen Beispiele, das bei python-fuse dabei ist, auch crasht? Wäre damit wohl einfacher ein Issue eröffnen zu können. Letztlich muss das zugrundeliegende Problem erstmal im Python-Modul gelöst werden. Als Python-Programmierer erwarte ich Exceptions aber keine Segfaults.


    Weil solche Fehler im EPG ja nicht so unwahrscheinlich sind wird man aber um ein kreatives "Fixen" von kaputtem Encoding auf Dauer kaum rumkommen.

  • Sehe gerade: Ganz so einfach ist das nicht mit dem "beliebigen Umkodieren". Man muss ja immer den Pfad halten der zur "echten" Datei führt. Aktuell wird dafür der tatsächliche Pfad im Fuse-Dateisystem genutzt.


    Eigentlich müsste das Fuse-Modul die "vergurkten" Pfade einfach durchreichen. Sieht dann komisch aus, aber besser als nichts.

  • Bekommst du das hin das eines der einfachen Beispiele, das bei python-fuse dabei ist, auch crasht?

    Ja, es genügt, wenn man in https://github.com/libfuse/pyt…ster/example/hello.py#L24 einen nicht einfach mit errors='strict' in UTF-8 enkodierbaren Pfad bzw. Dateinamen setzt (also z.B. hello_path = b'/hello\x99'.decode('utf-8', errors='surrogateescape')) und sich den Inhalt des Wurzelverzeichnis des fuse-Dateisystems mit ls anzeigen lässt.


    Letztlich muss das zugrundeliegende Problem erstmal im Python-Modul gelöst werden.

    Fürs Listen von Dateien ist das ja wie oben gezeigt nicht schlimm - da sorgt man halt dafür, dass die Enkodierung mit passenden Escape-Zeichen für nicht UTF-8 konforme Zeichen passiert.


    Wenn ich das richtig aus der Dokumentation der Python C-API herauslese, wird das eklig das korrekte Lesen von Pfaden mit nicht UTF-8 Zeichen im C-Code zu fixen - da muss man überall, wo das fuse-Modul einen char* mit den Bytes für den Pfad durch den UTF-8 Decoder schickt, um einen Python-String draus zu machen einen Custom Converter einbauen, damit er die Umwandlung mit 'surrogateescape' Error-Handler macht - das wären über 60 Stellen im Code und da man dann das korrekte "s" im Format-String durch ein "O&" ersetzen und die Convertermethode als zusätzlichen Parameter nach dem path angeben muss, ist das nicht mit suchen und ersetzen getan, gerade wenn man das noch "schön" kapseln will, so dass es die Abwärtskompatibilität zu alten Python- und FUSE-Versionen nicht kaputt macht... :§$%

    yaVDR-Dokumentation (Ceterum censeo enchiridia esse lectitanda.)

  • Abwärtskompatibilität zu Python 2 kann man, seit Python 2 offiziell abgekündigt ist, eigentlich eh vergessen.


    Sieht aber auch nicht so aus als würden die Python-Bindings auf libfuse sonderlich üppig gepflegt. Als Issue würde ich das aber trotzdem aufmachen. Segfaults darf es mit Python nie geben. Wenn stattdessen eine Exception geworfen wird wäre ich ja schon zufrieden.


    In einem Test hatte ich gerade schon eine Art "Übersetzungstabelle" für Datei-Pfade laufen. Allerdings eher als Hack. Ich muss mich da nochmal etwas ausführlicher mit befassen. Es gibt in vdrnfofs zig verschiedenen "Caches". Keine Ahnung welcher da für was gut ist und vor allem ob die überhaupt alle sinnvoll sind.

  • Heureka :)

    Wer Ubuntu 20.04 nutzt, kann mal probieren die angehängte Datei zu entpacken und mit der darin enthaltenen Shared Library die vorhandene /usr/lib/python3/dist-packages/fuseparts/_fuse.cpython-38-x86_64-linux-gnu.so zu ersetzen.

    Danke herzlichst, ja, mit der modifizierten library stürzt vdrnfofs nicht mehr ab.

  • Möglicher Fix ist im GIT. Testen mit einer gepatchten Library bringt aber natürlich jetzt nicht viel :P


    Mit der Anpassung hat man prinzipiell freie Wahl wie die Aufnahmen benannt werden. Der Name der Aufnahme ist nicht mehr an ihren echten Pfad im Dateisystem gebunden.


    Das klappt nicht mit kaputten Zeichen in einem echten Unterordner. Die bitte sauber halten. Sonst wird es echt zu komplex.

  • Hier ist noch der vollständige Patch für python-fuse, der sowohl das De- als auch das Encoding von Pfaden gerade zieht, die nicht-UTF8 Zeichen enthalten (die Python C-API ist hübsch-hässlich): fix_readdir_encoding_crash.patch


    Und für die Ubuntu 20.04 Nutzer das damit erstellte Modul: _fuse.cpython-38-x86_64-linux-gnu.zip

    yaVDR-Dokumentation (Ceterum censeo enchiridia esse lectitanda.)

  • Wow. Doch ein ziemlicher Aufwand. Gute Arbeit!


    Kannst du das als Pull-Request für python-fuse einstellen? Für Arch will ich auf keinen Fall ein Paket selber pflegen das schon in einem offiziellen Repo verfügbar ist. Einzige Chance es da rein zu bekommen wäre, wenn die eine Version mit dem Fix erstellen. Dann könnte ich "out of date" markieren um den Fix ins offizielle Paket zu bekommen.

  • Das kann ich am Wochenende machen - mir wäre es lieb, wenn das vorher noch ein paar Leute ausprobieren würden - ich habe schon ein Paket mit dem Patch in ppa:yavdr/experimental-main bauen lassen, damit das bequemer geht.

    yaVDR-Dokumentation (Ceterum censeo enchiridia esse lectitanda.)

  • Hab den Hack mal im "master" Branch wieder rausgehauen und in einen Unter-Branch "unicode-crashfix" verschoben.


    Aus diesem Branch habe ich dann eine Version 0.10.0 getaggt, die ich jetzt für vdr4arch paketiere. Ist für mich erstmal der einfachste Weg um das für Arch hinzubiegen.


    Ich muss am Wochenende mal schauen ob ich dazu komme den Patch von oben zu testen. Sollte eigentlich kein allzu großer Aufwand sein das PKGBUILD anzupassen um den Patch einzubauen und einen "crashenden Fall" habe ich hier lokal sowieso schon erzeugt.

  • Die Ubuntu-Version läuft hier jedenfalls - nochmal herzlichsten Dank, Seahawk!

  • Jetzt sieht das aber deutlich besser aus :)


    vdr-User-# 755 to_h264 chk_r vdr-transcode github

  • Code
    vdrnfofs on /mnt/vdrnfofs type fuse.vdrnfofs (rw,nosuid,nodev,relatime,user_id=0,group_id=0,allow_other)

    Wäre ein ro mount nicht sinnvoller?


    vdr-User-# 755 to_h264 chk_r vdr-transcode github

  • Mount-Parameter solltest du in der fstab nach Belieben setzen können.


    Selbst wenn man das beim manuellen Skriptaufruf hinbekommt: Ich will zumindest Löschen evtl. noch nachrüsten und ab dann wäre ein erzwungenes "ro" hinderlich.

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!