Me cuesta entender cómo funciona la codificación del nombre del archivo. En unix.SE encuentro explicaciones contradictorias.
Los nombres de los archivos se almacenan como caracteres.
Para citar otra respuesta: varias preguntas sobre la codificación de caracteres del sistema de archivos en Linux
[…] Como mencionas en tu pregunta, un nombre de archivo UNIX es solo una secuencia de caracteres; el kernel no sabe nada acerca de la codificación, que es completamente un concepto de espacio de usuario (es decir, de nivel de aplicación).
Si los nombres de archivo se almacenan como caracteres, debe haber algún tipo de codificación involucrada, ya que finalmente el nombre del archivo debe terminar como una secuencia de bits o bytes en el disco. Si el usuario puede elegir cualquier codificación para asignar los caracteres a una secuencia de bytes que se alimenta al núcleo, es posible crear cualquier secuencia de bytes para un nombre de archivo válido.
Suponga lo siguiente: un usuario utiliza una codificación aleatoria X , que traduce el archivo foo
a la secuencia de bytes α y lo guarda en el disco. Otros usos de los usuarios que codifica Y . En esta codificación, α se traduce en /
, que no está permitido como nombre de archivo. Sin embargo, para el primer usuario el archivo es válido.
Supongo que este escenario no puede suceder.
Los nombres de archivo se almacenan como blobs binarios
Para citar otra respuesta: ¿Qué codificación charset se usa para nombres de archivos y rutas en Linux?
Como han señalado otros, no hay realmente una respuesta a esto: los nombres de archivo y las rutas no tienen codificación; El sistema operativo solo se ocupa de la secuencia de bytes. Las aplicaciones individuales pueden elegir interpretarlas como codificadas de alguna manera, pero esto varía.
Si el sistema no trata con caracteres, ¿cómo se pueden prohibir caracteres particulares (por ejemplo, /
o NULL
) en los nombres de archivo? No hay noción de a /
sin una codificación.
Una explicación sería que el sistema de archivos puede almacenar nombres de archivos que contienen cualquier
carácter y son solo los programas de usuario los que tienen en cuenta una codificación que se atragantaría con los nombres de archivos que contienen caracteres no válidos. Eso, a su vez, significa que los sistemas de archivos y el núcleo pueden, sin ninguna dificultad, manejar los nombres de archivo que contienen a /
.
También supongo que esto está mal.
¿Dónde tiene lugar la codificación y dónde se plantea la restricción de no permitir caracteres particulares?
Respuestas:
Respuesta corta: restricciones impuestas en el núcleo de Unix / Linux / BSD,
namei()
función. La codificación se lleva a cabo en los programas de nivel de usuario comoxterm
,firefox
ols
.Creo que estás comenzando desde premisas incorrectas. Un nombre de archivo en Unix es una cadena de bytes con valores arbitrarios. Algunos valores, 0x0 (ASCII Nul) y 0x2f (ASCII '/') simplemente no están permitidos, no como parte de una codificación de caracteres de varios bytes, no como algo. Un "byte" puede contener un número que representa un carácter (en ASCII y algunas otras codificaciones) pero un "carácter" puede requerir más de 1 byte (por ejemplo, puntos de código por encima de 0x7f en la representación UTF-8 de Unicode).
Estas restricciones surgen de las convenciones de impresión de nombres de archivos y el conjunto de caracteres ASCII. Los Unix originales usaban bytes con valor ASCII '/' (numéricamente 0x2f) para separar partes de una ruta parcial o totalmente calificada (como '/ usr / bin / cat' tiene partes "usr", "bin" y "cat") . Los Unix originales usaban ASCII Nul para terminar las cadenas. Aparte de esos dos valores, los bytes en los nombres de archivo pueden asumir cualquier otro valor. Puede ver un eco de esto en la codificación UTF-8 para Unicode. Los caracteres ASCII imprimibles, incluido '/', toman solo un byte en UTF-8. UTF-8 para los puntos de código anteriores no incluye ningún byte de valor cero, excepto el carácter de control Nul. UTF-8 fue inventado para el Plan-9, El pretendiente al trono de Unix.
Los Unixes más antiguos (y parece que Linux) tenían una
namei()
función que solo mira las rutas de un byte a la vez, y divide las rutas en pedazos en bytes valorados 0x2F, deteniéndose en un byte de valor cero.namei()
es parte del núcleo Unix / Linux / BSD, por lo que es allí donde se aplican los valores de byte excepcionales.Tenga en cuenta que hasta ahora, he hablado de valores de bytes, no de caracteres.
namei()
no aplica ninguna semántica de caracteres en los bytes. Eso depende de los programas de nivel de usuario, comols
, que pueden ordenar los nombres de los archivos en función de los valores de bytes o valores de caracteres.xterm
decide qué píxeles se iluminarán para los nombres de archivo en función de la codificación de caracteres. Si no dicesxterm
que tienes nombres de archivo codificados con UTF-8, verás muchas tonterías cuando lo invoques. Sivim
no se compila para detectar codificaciones UTF-8 (o lo que sea, UTF-16, UTF-32), verá muchas tonterías cuando abra un "archivo de texto" que contenga caracteres codificados UTF-8.fuente
namei()
se abandonó alrededor de 1986. El uso de sistemas UNIX más nuevoslookuppn()
está basado en VFS.La cuestión es que al núcleo no le importa un poco cómo las aplicaciones interpretan los datos que se dan como nombre de archivo.
Imaginemos que tengo una aplicación C que trata exclusivamente con cadenas UTF-16. Y entro, a través de un método de entrada configurado correctamente, el símbolo ∯ (Unicode 0x222F) en el mensaje / diálogo "Guardar como".
Si la aplicación no realiza ninguna forma de traducción y la envía, en una cadena C (
char*
) simple y antigua para, por ejemplo,fopen
en modo de escritura, el núcleo no verá ∯, o incluso tratará de imaginarlo. Verá doschar
s, uno tras otro, con valores0x22 0x2F
(suponiendo caracteres de 8 bits y sin funnies en la biblioteca C ).Es decir, desde el punto de vista del núcleo, un char (
"
) válido seguido de/
(ASCII 0x2F).fopen
regresaráEISDIR
(es decir, "que se parece a un directorio y solicitó el modo de escritura").Si hubiera ingresado ∮ (Unicode
0x222E
), el núcleo habría visto dos caracteres finos y habría creado un archivo que, como se ve a través de una aplicación de habla ASCII, se nombraría".
.Si hubiera ingresado
a
en la aplicación como un nombre de archivo, y la aplicación lo pasó en UTF-16 al kernel, el kernel leería0x00 0x61
, y en realidad ni siquiera lo consideraría0x61
, porque0x00
ya termina la cadena, en la medida en que es preocupado. El mensaje de error sería el mismo que para un nombre de archivo vacío (ENOENT
creo).Por lo tanto, el núcleo realmente toma los datos como un blob. Es una corriente del
char
s. Los "caracteres" no válidos en su codificación de espacio de usuario de su elección son aquellos que generan0x00
o0x2F
("nulo" y/
) en su blob (representación binaria que se pasa al núcleo).fuente
0x00
y0x2F
están codificados en el núcleo. Eso a su vez significa que los directorios no están separados por a/
, sino por cualquier carácter que se asigne0x2F
en la codificación en uso./
no sea 0x2F; de hecho, podría no usar 8 bitschars
). El separador de directorios "tradicional" sí lo es/
. Eso es 0x27 en sistemas ASCII de 8 bits byte (no EBCDIC por ejemplo).a
cadena (terminada en nulo) .La separación de bytes frente a caracteres se produjo mucho después de que se diseñó Unix. Cuando se diseñó, el uso de las palabras solo transmitía algo sobre cómo se interpretaron 8 (o 6, o 9) bits, pero no se mencionaron las codificaciones de palabras .
Los nombres de archivo son secuencias de bytes. Se permite cualquier byte excepto 0x2f "/". Un byte que contiene 0x00 ni siquiera puede llegar al núcleo debido a su uso como un terminador de cadena. Una aplicación puede interpretar la secuencia de bytes de acuerdo con la codificación que elija. Si eso suena desordenado, supongo que lo es.
Hay más información en http://www.gtk.org/api/2.6/glib/glib-Character-Set-Conversion.html que puede resultarle útil.
fuente