Es fällt mir schwer zu verstehen, wie die Dateinamencodierung funktioniert. Auf unix.SE finde ich widersprüchliche Erklärungen.
Dateinamen werden als Zeichen gespeichert
Um eine andere Antwort zu zitieren: Mehrere Fragen zur Zeichencodierung im Dateisystem unter Linux
[…] Wie Sie in Ihrer Frage erwähnt haben, besteht ein UNIX-Dateiname nur aus einer Folge von Zeichen. Der Kernel weiß nichts über die Kodierung, die ein Konzept auf Benutzerbereichs- (dh Anwendungsebene) ist.
Wenn Dateinamen als Zeichen gespeichert werden, muss eine Art Codierung erforderlich sein, da der Dateiname schließlich als Bit- oder Byte-Sequenz auf der Festplatte gespeichert werden muss. Wenn der Benutzer eine Codierung auswählen kann , um die Zeichen einer Bytefolge zuzuordnen, die dem Kernel zugeführt wird, kann eine beliebige Bytefolge für einen gültigen Dateinamen erstellt werden.
Angenommen, ein Benutzer verwendet eine zufällige Codierung X , die die Datei foo
in die Bytefolge α übersetzt und auf der Festplatte speichert. Ein anderer Benutzer Verwendungen kodierend Y . Bei dieser Kodierung wird α übersetzt /
, was als Dateiname nicht erlaubt ist. Für den ersten Benutzer ist die Datei jedoch gültig.
Ich gehe davon aus, dass dieses Szenario nicht passieren kann.
Dateinamen werden als binäre Blobs gespeichert
Um eine andere Antwort zu zitieren: Welche Zeichensatzkodierung wird für Dateinamen und Pfade unter Linux verwendet?
Wie von anderen bemerkt, gibt es keine wirkliche Antwort darauf: Dateinamen und Pfade haben keine Kodierung; Das Betriebssystem behandelt nur die Reihenfolge der Bytes. Einzelne Anwendungen interpretieren sie möglicherweise so, dass sie auf irgendeine Weise codiert sind. Dies ist jedoch unterschiedlich.
Wenn das System keine Zeichen verarbeitet, wie können bestimmte Zeichen (z. B. /
oder NULL
) in Dateinamen verboten werden? Es gibt keine Vorstellung von einem /
ohne Kodierung.
Eine Erklärung wäre, dass das Dateisystem Dateinamen speichern kann, die beliebige
Zeichen enthalten, und dass nur die Benutzerprogramme, die eine Kodierung berücksichtigen, Dateinamen mit ungültigen Zeichen verschlüsseln würden. Dies bedeutet wiederum, dass Dateisysteme und der Kernel problemlos mit Dateinamen umgehen können, die a enthalten /
.
Ich gehe auch davon aus, dass dies falsch ist.
Wo findet die Codierung statt und wo besteht die Einschränkung, bestimmte Zeichen nicht zuzulassen?
Antworten:
Kurze Antwort: Einschränkungen im Unix / Linux / BSD-Kernel,
namei()
Funktion. Die Kodierung erfolgt in Programmen auf Benutzerebene wiexterm
,firefox
oderls
.Ich glaube, Sie gehen von falschen Voraussetzungen aus. Ein Dateiname in Unix ist eine Folge von Bytes mit beliebigen Werten. Einige Werte, 0x0 (ASCII Nul) und 0x2f (ASCII '/'), sind einfach nicht zulässig, nicht als Teil einer Mehrbyte-Zeichencodierung, und auch nicht. Ein "Byte" kann eine Zahl enthalten, die ein Zeichen darstellt (in ASCII und einigen anderen Codierungen), ein "Zeichen" kann jedoch mehr als 1 Byte erfordern (z. B. Codepunkte über 0x7f in der UTF-8-Darstellung von Unicode).
Diese Einschränkungen ergeben sich aus den Druckkonventionen für Dateinamen und dem ASCII-Zeichensatz. Die ursprünglichen Unixe verwendeten ASCII '/' (numerisch 0x2f) Bytes, um Teile eines teilweise oder vollständig qualifizierten Pfades zu trennen (wie '/ usr / bin / cat' hat Teile "usr", "bin" und "cat"). . Die ursprünglichen Unixe verwendeten ASCII Nul, um Zeichenfolgen zu beenden. Abgesehen von diesen beiden Werten können Bytes in Dateinamen einen anderen Wert annehmen. Sie können ein Echo davon in der UTF-8-Codierung für Unicode sehen. Druckbare ASCII-Zeichen, einschließlich '/', benötigen in UTF-8 nur ein Byte. UTF-8 für die obigen Codepunkte enthält keine nullwertigen Bytes mit Ausnahme des Steuerzeichens Nul. UTF-8 wurde für Plan-9, The Pretender to the Throne of Unix, erfunden.
Ältere Unixe (und es sieht aus wie Linux) hatten eine
namei()
Funktion, die nur die Pfade eines Bytes aufteilte und die Pfade bei 0x2F-Bytes in Teile zerlegte, wobei sie bei einem Null-Byte stoppten.namei()
ist Teil des Unix / Linux / BSD-Kernels, daher werden hier die außergewöhnlichen Bytewerte erzwungen.Beachten Sie, dass ich bisher von Bytewerten gesprochen habe, nicht von Zeichen.
namei()
erzwingt keine Zeichensemantik für die Bytes. Dies hängt von den Programmen auf Benutzerebene abls
, die Dateinamen nach Byte- oder Zeichenwerten sortieren.xterm
entscheidet anhand der Zeichenkodierung, welche Pixel für Dateinamen aufleuchten. Wenn Sie nicht sagen, dassxterm
Sie UTF-8-codierte Dateinamen haben, werden Sie beim Aufrufen viel Kauderwelsch sehen. Wennvim
es nicht kompiliert wurde, um UTF-8-Codierungen (oder was auch immer, UTF-16, UTF-32) zu erkennen, wird beim Öffnen einer "Textdatei" mit UTF-8-codierten Zeichen viel Kauderwelsch angezeigt.quelle
namei()
wurde um 1986 aufgegeben. Neuere UNIX-Systeme verwendenlookuppn()
VFS-basierte.Die Sache ist, dem Kernel ist es egal, wie die Anwendungen die Daten interpretieren, die er als Dateinamen angibt.
Stellen wir uns vor, ich habe eine C-Anwendung, die sich ausschließlich mit UTF-16-Zeichenfolgen befasst. Und ich gebe über eine richtig konfigurierte Eingabemethode das Symbol ∯ (Unicode 0x222F) in die Eingabeaufforderung / den Dialog "Speichern unter" ein.
Wenn die Anwendung keine Übersetzung ausführt und diese in einem einfachen alten C-String (
char*
) beispielsweisefopen
im Schreibmodus sendet, wird der Kernel el nicht sehen oder versucht, sich das auch nur vorzustellen. Es werdenchar
nacheinander zwei s mit Werten0x22 0x2F
angezeigt (vorausgesetzt 8-Bit-Zeichen und keine lustigen Zeichen in der C-Bibliothek ).Aus Sicht des Kernels ist dies ein gültiges char (
"
) gefolgt von/
(ASCII 0x2F).fopen
wird zurückgegebenEISDIR
(dh "das sieht aus wie ein Verzeichnis und Sie haben den Schreibmodus angefordert!").Wenn ich ∮ (Unicode
0x222E
) eingegeben hätte , hätte der Kernel zwei feine Zeichen gesehen und eine Datei erstellt, die, wie durch eine ASCII-sprechende Anwendung gesehen, benannt würde".
.Wenn ich
a
in der Anwendung einen Dateinamen eingegeben hätte und die Anwendung ihn in UTF-16 an den Kernel weiterleitet, würde der Kernel dies lesen0x00 0x61
und dies auch gar nicht berücksichtigen0x61
, da0x00
der String bereits beendet wird, so wie er ist besorgt. Die Fehlermeldung ist die gleiche wie bei einem leeren Dateinamen (ENOENT
glaube ich).Der Kernel nimmt die Daten also tatsächlich als Blob. Es ist ein Strom von
char
s. Die ungültigen "Zeichen" in Ihrer User-Space-Codierung Ihrer Wahl sind diejenigen, die0x00
oder0x2F
("null" und/
) in ihrem Blob (binäre Darstellung, die an den Kernel übergeben wird) generieren .quelle
0x00
und0x2F
sind im Kernel fest codiert. Dies bedeutet wiederum, dass Verzeichnisse nicht durch ein getrennt werden/
, sondern auf welche Zeichen0x2F
in der verwendeten Codierung abgebildet werden./
nicht 0x2F ist - möglicherweise wird 8-Bit nicht verwendetchars
.) Das "traditionelle" Dir-Trennzeichen lautet/
. Das ist 0x27 auf 8-Bit-ASCII-Systemen (zum Beispiel nicht EBCDIC).a
Zeichenfolge ergibt .Die Trennung von Bytes und Zeichen erfolgte viel nach der Entwicklung von Unix. Als es entworfen wurde, vermittelte die Verwendung der Wörter nur etwas darüber, wie 8 (oder 6 oder 9) Bits interpretiert wurden, aber die Wortcodierungen wurden nicht erwähnt.
Dateinamen sind Folgen von Bytes. Jedes Byte außer 0x2f "/" ist zulässig. Ein Byte mit 0x00 kann aufgrund seiner Verwendung als String-Terminator nicht einmal zum Kernel durchdringen. Eine Anwendung kann die Folge von Bytes gemäß der von ihr gewählten Codierung interpretieren. Wenn das chaotisch klingt, dann ist es es wohl.
Weitere Informationen finden Sie unter http://www.gtk.org/api/2.6/glib/glib-Character-Set-Conversion.html .
quelle