MAX_SUBTITLE_LENGTH und VFAT_MAX_FILENAME

  • Da dieses Thema immer wieder hochkommt habe ich mir das jetzt mal etwas genauer angeschaut. Dabei sind mir einige Ungereimtheiten aufgefallen, die ich hier mal zur Diskussion stellen möchte. Wenn im Folgenden Puffergrößen bzw. Stringlängen genannt werden, so sind diese immer inclusive der abschließenden 0 zu verstehen.


    Zunächst mal die Fakten:


    - MAX_SUBTITLE_LENGTH wird in recording.c verwendet, und zwar als Anzahl der Bytes, die der "Subtitle" maximal lang sein darf. Ist er länger, werden so viele UTF-8 Symbole genommen, wie in MAX_SUBTITLE_LENGTH reinpassen.
    Der "Title" wird hier nicht entsprechend behandelt (obwohl der ja auch länger sein könnte), und es wird auch nicht berücksichtigt, daß über das TITLE und EPISODE Macro ein Name wie "TITLE-EPISODE" gebaut werden könnte, der wiederum länger als MAX_SUBTITLE_LENGTH sein könnte.


    - VFAT_MAX_FILENAME wird in timers.c verwendet, und zwar als Anzahl der UTF-8 Symbole, die der Filename maximal lang sein darf (wobei in cTimer::Parse() nur der Teil nach dem letzten FOLDERDELIMCHAR berücksichtigt wird, falls vorhanden, ansonsten der ganze Filename).


    - Die maximale Länge (in Byte) eines Filenamens in einem Timer ist MaxFileName (256).


    - An anderen Sellen benutzt VDR PATH_MAX bzw. NAME_MAX.


    Wie schon von so manchem richtig angemerkt wurde, ist das ein ziemliches Durcheinander. Da wird einmal die Anzahl der Bytes benutzt, ein anderes mal die Anzahl der UTF-8 Symbole. Mal wird der ganze Filename limitiert, dann wieder nur ein Teil davon. Und schließlich wird mit zwei verschiedenen Macros gearbeitet, die aber den gleichen Wert haben.


    Fragt sich also, wie man das in den Griff bekommen kann.
    Hier mal ein paar Überlegungen zu möglichen Änderungen:


    - Die Gesamtlänge eines Filenamens in einem Timer wird dynamisch gehandhabt, und es wird darauf geachtet, daß ein einzelner Namensbestandteil nicht größer als NAME_MAX wird (unabhängig von VFAT oder nicht).
    - Unter Linux ist NAME_MAX 255 und PATH_MAX 4096, somit sollte es also in der Praxis keine Probleme geben.
    - Der "name" sowie der "text" eines SI::ShortEventDescriptor können jeweils maximal 256 (255?) Byte lang sein, somit ist bei der Verwendung dieser Strings auf einem reinen Linux-System keine Spezialbehandlung erforderlich, es sei denn, sie werden über das TITLE bzw. EPISODE Macro zusammengebaut oder mit anderen Strings kombiniert.
    - Unter Windows (VFAT?) ist anscheinend die maximale Länge des gesamten Pfadnamens (also Directories plus Filename) auf 255 Zeichen beschränkt. Zumindest hat das ein Versuch auf meinem Laptop mit Windows XP ergeben. Laut http://en.wikipedia.org/wiki/Long_filename sind das 255 UTF-16 Zeichen, daher wohl auch die Berechnung mit UTF-8 Symbolen anstatt Bytes in timers.c.


    Schlußfolgerungen:


    - Die Sonderbehandlung für den VFAT-Fall an den Stellen, wo VFAT_MAX_FILENAME verwendet wird, entfällt bzw. wird allgemein auf NAME_MAX begrenzt.
    - Falls die --vfat Option eingeschaltet ist, werden Filenamen in cRecording::cRecording(cTimer *Timer, const cEvent *Event) (und nur dort!) so verkürzt, daß sie den VFAT-Bedingungen entsprechen.


    Die VFAT-Namensverkürzung folgt diesen Regeln:


    - Ein Pfadname für eine an einer Aufzeichnung beteiligte Datei ist folgendermaßen aufgebaut:
    /videodir/folder.../name/YYYY-MM-DD.hh.mm.channel-instance.rec/00001.ts
    wobei die *.ts-Dateien mit 8 Zeichen die längsten Namen haben.
    - Der Teil ab YYYY wird automatisch generiert und verletzt mit Sicherheit nicht die 255er Grenze.
    - Der Teil /videodir/ ist nur auf dem Linux-System sichtbar, unter Windows kann dieses Verzeichnis
    vollkommen anders heißen, ja es könnte sogar ein sehr langer Pfad sein, was allerdings äußerst
    ungeschickt wäre. Daher gehen wir der Einfachheit halber mal davon aus, daß der Name des
    Verzeichnisses unter Windows zumindest nicht länger sein wird als unter Linux.
    - Die Gesamtlänge des Pfadnamens darf bei VFAT 255 Zeichen nicht überschreiten. Ist sie größer als 255,
    so wird zunächst der Anteil "name" so lange verkürzt, bis die Bedingung erfüllt ist, oder nur noch ein Zeichen
    übrig ist.
    - Reicht die Verkürzung von "name" nicht aus, so werden schrittweise alle "folder" von rechts nach links
    ebenso behandelt. Der "/videodir"-Teil bleibt aber unverändert.
    - Reicht selbst die Verkürzung aller zwischengeschalteter Directories nicht aus, so werden von rechts nach
    links so lange Directories entfernt, bis die Gesamtlänge 255 Zeichen nicht mehr übersteigt. Dieser Fall dürfte
    allerdings in der Praxis kaum auftreten, dann dazu müsste jemand schon mehr als 100 Unterverzeichnisse
    haben - wer macht das schon...



    Ich bitte um sachliche Kommentare bzw. Meinungen hierzu.
    Vielleicht hat ja auch jemand eine viel bessere Idee, wie man das handhaben sollte.
    Sobald aber dieser Thread (wie leider so viele in letzter Zeit) in saudumme Bemerkungen oder persönliche Angriffe abgleitet, bin ich sofort raus hier und es bleibt für die Version 2.0 alles so, wie es jetzt ist. Also bitte Gehirn einschalten vor dem Schreiben ;-).


    Klaus

  • Den Begriff --vfat fand ich schon immer verwirrend, weil eigentlich hat die ganze Sache ja nix mit dem Dateisystem vfat zu tun. Die meisten dürften kein vfat als Heimat fürs Videoverzeichnis nutzen. Und hier gibts ja öfter Fragen von Leuten die den Bezug zwischen den #xx Ersetzungen und --vfat nicht erkennen.



    Ich fände es viel logischer wenn es statdessen einen Parameter --max_path <integer, default 255> (oder so in der Art benannt) gäbe mit der der Nutzer die Länge festlegen kann. Dann ist man von der aktuellen Windowsversion unabhängig, und der Mount Path auf der Windows Kiste könnte vom Nutzer auch nach Wunsch berücksichtigt werden.


    Ferner einen zweiten der für portable Dateinamen zuständig ist, d.h. wenn gesetzt dann werden bestimmte Zeichen durch die #xx Variante ersetzt (ferner Leerzeichen und Punkte am Anfang/Ende von Datei-/Verzeichnisnamen). Weil das betriff ja nicht nur Windows, es gibt ja auch noch andere Betriebsysteme. Also sowas wie --portable_names (etwas holperig, aber mir fällt jetzt nix besseres ein)


    Das nur mal so meine Gedanken zum Thema. Einfach mal so hingeschrieben.



    Ansonsten, dein "Die VFAT-Namensverkürzung folgt diesen Regeln" Absatz scheint logisch und korrekt, ich denke auch du hast da alles bedacht.


    cu

  • - VFAT_MAX_FILENAME wird in timers.c verwendet, und zwar als Anzahl der UTF-8 Symbole, die der Filename maximal lang sein darf

    Apropos: Unter VDR 1.6 gibt es das Problem, dass UTF-8-Sequenzen manchmal in der Mitte geteilt werden. Ist das unter 1.7 auch noch so? (Ich habe die Sache damals nicht weiter verfolgt, sondern kurzerhand VFAT_MAX_FILENAME und MAX_SUBTITLE_LENGTH auf 255 gesetzt und neu kompiliert. ;))


    - Unter Windows (VFAT?) ist anscheinend die maximale Länge des gesamten Pfadnamens (also Directories plus Filename) auf 255 Zeichen beschränkt. Zumindest hat das ein Versuch auf meinem Laptop mit Windows XP ergeben. Laut http://en.wikipedia.org/wiki/Long_filename sind das 255 UTF-16 Zeichen, daher wohl auch die Berechnung mit UTF-8 Symbolen anstatt Bytes in timers.c.

    Es sind sogar 260. ;) Das schließt den Laufwerksnamen (x:\) bzw. Freigabenamen (\\server\freigabe\) und das NUL am Ende mit ein. Was tatsächlich übrig bleibt, ist also vom Einzelfall abhängig und lässt sich nur schwer vorhersagen.


    Ich fände es viel logischer wenn es statdessen einen Parameter --max_path <integer, default 255> (oder so in der Art benannt) gäbe mit der der Nutzer die Länge festlegen kann. Dann ist man von der aktuellen Windowsversion unabhängig, und der Mount Path auf der Windows Kiste könnte vom Nutzer auch nach Wunsch berücksichtigt werden.

    Da stimme ich zu. Wobei ich den Standardwert deutlich niedriger setzen würde, auf 200 oder so. Das sollte in den meisten Fällen noch genug Platz für den Server- bzw. Freigabenamen lassen, und wer wirklich noch längere Verzeichnisnamen braucht, kann das immer noch ändern.

    Give root password for maintenance (or type Control-D to continue): _

  • Kann bitte mal jemand, der UTF-8 verwendet, folgendes Script laufen lassen (am besten in einem leeren Verzeichnis, das danach gelöscht werden kann)?


    Es geht darum herauszufinden, ob unter Linux UFT-8-Zeichen in Filenamen als ein Byte oder mehrere zählen.


    Bitte die resultierenden Fehlermeldungen hier posten.


    Klaus

  • Das sieht so aus:
    http://pastebin.com/A0CSjLCp


    Deutsche Umlaute brauchen immer zwei Bytes, prinzipell kann es auch länger werden (z.B. für Sonderzeichen, andere Alphabete usw.: http://de.wikipedia.org/wiki/UTF-8#Kodierung)

    yaVDR-Dokumentation (Ceterum censeo enchiridia esse lectitanda.)

  • Code
    ./test.sh: Zeile 9: 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890a23456: Der Dateiname ist zu lang
    ./test.sh: Zeile 9: 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890a234567: Der Dateiname ist zu lang
    ./test.sh: Zeile 9: 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890a2345678: Der Dateiname ist zu lang
    ./test.sh: Zeile 9: 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890a23456789: Der Dateiname ist zu lang
    ./test.sh: Zeile 14: 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890ä2345: Der Dateiname ist zu lang
    ./test.sh: Zeile 14: 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890ä23456: Der Dateiname ist zu lang
    ./test.sh: Zeile 14: 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890ä234567: Der Dateiname ist zu lang
    ./test.sh: Zeile 14: 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890ä2345678: Der Dateiname ist zu lang
    ./test.sh: Zeile 14: 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890ä23456789: Der Dateiname ist zu lang


    Das Script in einem Unterverszeichnis /home/user111/Test gestartet


    locale:
    LANG=de_DE.UTF-8
    LC_CTYPE="de_DE.UTF-8"
    LC_NUMERIC="de_DE.UTF-8"
    LC_TIME="de_DE.UTF-8"
    LC_COLLATE="de_DE.UTF-8"
    LC_MONETARY="de_DE.UTF-8"
    LC_MESSAGES="de_DE.UTF-8"
    LC_PAPER="de_DE.UTF-8"
    LC_NAME="de_DE.UTF-8"
    LC_ADDRESS="de_DE.UTF-8"
    LC_TELEPHONE="de_DE.UTF-8"
    LC_MEASUREMENT="de_DE.UTF-8"
    LC_IDENTIFICATION="de_DE.UTF-8"
    LC_ALL=

    VDR 2.6.6: ASUS Prime X470-PRO, Ryzen 7 5700X, 64GB, 6TB HD, GT1030, Fedora 39 Kernel 6.8 X86_64, Devicebonding 2 x 1 auf 2, TT6400, DVBSky S952 V3

    Git-Repo: gitlab.com/kamel5

  • Hallo Klaus,


    anbei die Ausgabe des Skripts:

    Gruß
    Frodo

  • Das sieht so aus:
    http://pastebin.com/A0CSjLCp


    Deutsche Umlaute brauchen immer zwei Bytes, prinzipell kann es auch länger werden (z.B. für Sonderzeichen, andere Alphabete usw.: http://de.wikipedia.org/wiki/UTF-8#Kodierung)


    Danke (auch an "kamel5" und "frodo").


    Das Problem ist, daß unter Windows, soweit ich das verstehe, ein kompletter Filename (mit allen Directories) maximal 255 16-bit Unicode-Zeichen lang sein kann.
    Bei der Limitierung der Filenamen unter Linux kann ich einfach den einzelnen Namen auf NAME_MAX beschränken (wobei UTF-8-Zeichen als entsprechend viele Bytes zählen) und den kompletten Namen (mit Directories) auf PATH_MAX, wobei die Directory-Delimiter ('/') mit zählen.
    Soll ich jetzt für Windows UTF-8-Zeichen nur als *ein* Zeichen zählen? Und was ist mit den Directory-Delimitern? Soweit ich das sehe zählen die bei Windows nicht mit - oder doch?
    Auf der sicheren Seite sind wir auf jeden Fall, wenn ich UTF-8-Zeichen als die enstprechende Zahl von Bytes zähle und die Delimiter mitzähle. Dann passt es unter Linux auf jeden Fall, und unter Windows ist ein Pfadname evtl. kürzer als es theoretisch möglich wäre.


    Klaus

  • Moin!


    Auf der sicheren Seite sind wir auf jeden Fall, wenn ich UTF-8-Zeichen als die enstprechende Zahl von Bytes zähle und die Delimiter mitzähle. Dann passt es unter Linux auf jeden Fall, und unter Windows ist ein Pfadname evtl. kürzer als es theoretisch möglich wäre.


    Das hört sich doch gut an. Ob da mal ein paar Zeichen am Ende fehlen, ist ja kein Beinbruch.


    Lars.

  • Es geht darum herauszufinden, ob unter Linux UFT-8-Zeichen in Filenamen als ein Byte oder mehrere zählen.


    Das ging mir hier etwas zu sehr unter. Denn es ist wichtig im Hinterkopf zu behalten das...


    Unter Linux sind Dateinamen nur eine Folge von Bytes, es gibt dort weder UTF-8 noch de_DE ISO-8859-1. Nur Bytes ohne irgendeine Bedeutung.


    Das ist sofern relevant das man nach Konvertierungen den Dateinamen evtl. nicht wiederfindet.
    Angenommen das System läuft auf utf-8 und findet eine Datei (die z.B. ein "ä" enthalt) die erstellt wurde als das System früher noch unter de_DE ISO-8859-1 lief. Dann enthält die Bytefolge ein 0xe4 (halt das "ä" in de_DE ISO-8859-1), das ist aber in uft-8 ein ungültiges Byte (weil es ist > 7bit und ergibt keine gültige utf-8 Sequenz) und wird ülicherweise durch das Fragezeichen in einer Raute ersetzt (wenn man allg. utf-8 Funktionen nutzt die solche Fehler behandeln).
    Nimmt man jetzt diesen utf-8 String als Dateinamen um wieder auf die Datei zuzugreifen wird es fehlschlagen.




    Und das beantwortet auch die Frage, es zählt als Länge die Anzahl der Bytes die du als Dateiname übergibts. Ob die Bytes als utf-8, de_DE ISO-8859-1 oder base64 Kodierung Sinn ergeben ist dem Dateisystem egal.


    cu

  • Also Microsoft meint dazu folgendes: (http://msdn.microsoft.com/en-u…28v=vs.85%29.aspx#maxpath)


    Maximum Path Length Limitation


    In the Windows API (with some exceptions discussed in the following paragraphs), the maximum length for a path is MAX_PATH, which is defined as 260 characters. A local path is structured in the following order: drive letter, colon, backslash, name components separated by backslashes, and a terminating null character. For example, the maximum path on drive D is "D:\some 256-character path string<NUL>" where "<NUL>" represents the invisible terminating null character for the current system codepage. (The characters < > are used here for visual clarity and cannot be part of a valid path string.)


    Note File I/O functions in the Windows API convert "/" to "\" as part of converting the name to an NT-style name, except when using the "\\?\" prefix as detailed in the following sections.
    [...]
    There is no need to perform any Unicode normalization on path and file name strings for use by the Windows file I/O API functions because the file system treats path and file names as an opaque sequence of WCHARs. Any normalization that your application requires should be performed with this in mind, external of any calls to related Windows file I/O API functions.


    When using an API to create a directory, the specified path cannot be so long that you cannot append an 8.3 file name (that is, the directory name cannot exceed MAX_PATH minus 12).


    Ich weiss jetzt nicht, ob das weiterhilft ...


    Gruß


    eggi1973

  • Was Microsoft dazu meint ist eigentlich vollkommen egal ;)


    Es gibt abhängig von der Windows Version, dem aktuellen Service Pack, dem verwendeten Dateisystem, der genutzen API und der verwendeten Software so viele verschiedene Limits das man da keine klare Grenze festlegen kann.
    Und evtl. will man ja auch die Kommandozeile nutzen, und wie lang eine Kommandozeile max. werden darf ist wieder nen ganz anderes Thema (da ist auch bei jedem anderst) ;)


    Ich habe z.B. so rein praktisch überhaupt keine Probleme mit Pfadlängen von >1000 Zeichen.



    Man muss hier einfach mal mutig willkürlich nen relativ kleines Limit festlegen, ne korrekte Antwort wird man niemals finden.



    BTW: Wikipedia meint zu NTFS -> Dateinamen 255 Zeichen (egal was für welche) und Pfade circa 32.767 Zeichen ;)


    cu


  • Es sind sogar 260. ;) Das schließt den Laufwerksnamen (x:\) bzw. Freigabenamen (\\server\freigabe\) und das NUL am Ende mit ein. Was tatsächlich übrig bleibt, ist also vom Einzelfall abhängig und lässt sich nur schwer vorhersagen.


    Was Microsoft dazu meint ist eigentlich vollkommen egal ;)


    Ich denke, es ist nicht wirklich egal, was der Hersteller/Entwickler des betroffenen FS dazu meint, aber es macht nicht viel Sinn, bereits gepostete Infos nochmals zu posten. :wand :wand Immerhin bin ich auf den identen Link gekommen :D


    Schönen Tag,


    eggi1973

  • Anbei mal ein Patch, der die neue Option --dirnames implementiert.


    Den Filenamen in cTimer dynamisch zu machen war mir dann doch etwas zu aufwendig, daher habe ich ihn auf 2xNAME_MAX vergrößert. Damit kann er die maximal mögliche Länge von "Title" und "Short text" eines EPG-Events aufnehmen, was wohl reichen sollte.


    Der HISTORY-Eintrag für diese Änderung lautet:

    Code
    - cTimer no longer does any special "VFAT" handling to shorten directory names to 40
      characters. When a string is used as a directory name for a recording, the maximum
      length of the directory path, as well as the individual directory names, is now
      limited to the values specified by the new command line option --dirnames (see
      man vdr(1) for details). For backwards compatibility the option --vfat is still
      available and has the same effect as --dirnames=250,40,1.
    - The macro MaxFileName is now obsolete and may be removed in future versions. Use
      NAME_MAX directly instead.


    Bitte schaut euch das mal an und probiert es aus.


    Klaus

  • Beim nochmaligen Drüberschauen habe ich soeben bemerkt, daß da noch ein Rest von meiner ursprünglichen Testumgebung drin war.
    Bitte diesen Patch nachträglich anwenden:


    Klaus

  • O je, und vor lauter Namensverkürzung habe ich ganz übersehen, das MAX_SUBTITLE_LENGTH in recording.c zu eliminieren!
    Neuer Patch folgt in Kürze...


    Edit: OK, im Anhang nochmal der komplette Patch, mit den jüngsten Änderungen.


    Falls jemand nur die Änderung für MAX_SUBTITLE_LENGTH haben will:


    Klaus

Jetzt mitmachen!

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