Unix dosya adı kodlamasını anlama


25

Dosya adı kodlamasının nasıl çalıştığını anlamakta zorlanıyorum. Unix.SE'de çelişkili açıklamalar buluyorum.

Dosya adları karakter olarak saklanır

Başka bir cevap alıntı yapmak için: Linux'ta dosya sistemi karakter kodlaması hakkında birkaç soru

[…] Sorunuzda bahsettiğiniz gibi, bir UNIX dosya adı sadece bir karakter dizisidir; çekirdek, tamamen bir kullanıcı-alanı (yani uygulama seviyesi) konsepti olan kodlama hakkında hiçbir şey bilmiyor.

Dosya adları karakter olarak saklanırsa, sonunda dosya adının diskte bir bit veya bayt dizisi olması gerektiğinden, bir tür kodlamanın dahil olması gerekir. Kullanıcı , karakterleri çekirdeğe beslenen bir bayt dizisine eşlemek için herhangi bir kodlamayı seçebiliyorsa , geçerli bir dosya adı için herhangi bir bayt dizisi oluşturmak mümkündür .

Aşağıdakileri yapın: Bir kullanıcı , dosyayı bayt dizisine α dönüştüren ve diske kaydeden bir rastgele X kodlaması kullanır . Başka bir kullanıcı Y kodlamasını kullanır . Bu kodlamada α bir dosya adı olarak izin verilmeyen bir çeviriye dönüşür . Ancak, ilk kullanıcı için dosya geçerlidir.foo/

Bu senaryonun gerçekleşemeyeceğini varsayıyorum.

Dosya adları ikili blob olarak saklanır

Başka bir cevap alıntı yapmak için: Hangi karakter kümesi kodlaması Linux'ta dosya adları ve yollar için kullanılır?

Başkaları tarafından belirtildiği gibi, bunun gerçekten bir cevabı yoktur: dosya isimleri ve yolların kodlaması yoktur; İşletim sistemi yalnızca bayt sırası ile ilgilenir. Bireysel uygulamalar onları bir şekilde kodlanmış olarak yorumlamayı seçebilir, ancak bu değişebilir.

Sistem karakterlerle ilgilenmezse , dosya adlarında belirli karakterler (örneğin /veya NULL) nasıl yasaklanabilir? / Kodlama olmadan bir kavram yoktur .

Bir açıklama, dosya sisteminin herhangi bir karakter içeren dosya adlarını saklayabileceği ve sadece geçersiz karakterler içeren dosya adlarında boğulacak kodlamayı dikkate alan kullanıcı programları olabilir. Bunun anlamı, dosya sistemlerinin ve çekirdeğin, herhangi bir zorlukla karşılaşmadan, a içeren dosya adlarını kullanabileceği anlamına gelir /.

Bunun yanlış olduğunu da varsayıyorum.

Kodlama nerede gerçekleşir ve kısıtlama belirli karakterlere izin vermeme durumunda nerede yapılır?


Boş, tüm kodlamalarda aynıdır (0).
Kevin,

2
@Kevin Tam olarak değil: UTF-16 veya UCS-4 (= UTF-32) veya ASCII'nin bir uzantısı olmayan diğer çok baytlı kodlamalarda değil.
Gilles 'SO- kötülük'

1
Aslında, Riccardo Murri'nin cevabı karakterlerden değil baytlardan bahsetmeliydi . Çoğu dosya sistemi bayt depolar.
Gilles 'SO- kötülük olmayı'

@Gilles: Yine bir başka sefer gerçekten ne seyretmek bkz yazılı .
Incnis Mrsi 17:15

Yanıtlar:


25

Kısa cevap: Unix / Linux / BSD çekirdeğinde, namei()fonksiyonunda getirilen kısıtlamalar . Kodlama xterm, firefoxveya gibi kullanıcı seviyesi programlarında gerçekleşir ls.

Bence yanlış yerlerden başlıyorsun. Unix'deki bir dosya adı, keyfi değerleri olan bir bayt dizisidir. Çok baytlık bir karakter kodlamasının bir parçası olarak, hiçbir şeye değil, birkaç değere, 0x0 (ASCII Nul) ve 0x2f (ASCII '/') izin verilmez. Bir "bayt" bir karakteri temsil eden bir sayı içerebilir (ASCII ve diğer bazı kodlamalarda), ancak bir "karakter" 1 bayttan daha fazlasını gerektirebilir (örneğin, Unicode UTF-8 gösteriminde 0x7f'in üzerindeki kod noktaları).

Bu kısıtlamalar, dosya adı yazdırma kurallarından ve ASCII karakter kümesinden kaynaklanır. Orijinal Unix'ler, kısmen ya da tamamen nitelikli bir yolun parçalarını ayırmak için bayt değerli ASCII '/' (sayısal olarak 0x2f) kullanmıştır ('/ usr / bin / cat' gibi "usr", "bin" ve "cat" parçalarına sahiptir) . Orijinal Unix'ler dizeleri sonlandırmak için ASCII Nul kullandılar. Bu iki değer dışında, dosya adlarındaki bayt başka bir değer alabilir. Bunun ekosunu Unicode için UTF-8 kodlamasında görebilirsiniz. '/' Dahil yazdırılabilir ASCII karakterleri UTF-8'de yalnızca bir bayt alır. Yukarıdaki kod noktaları için UTF-8, Nul denetim karakteri dışında hiçbir Sıfır değerli bayt içermez. UTF-8, Unix'in Tahtı Öncüsü Plan-9 için icat edildi.

Eski Unix'ler (ve Linux'a benziyor) namei()bir anda sadece bir bayt yoluna bakan ve 0 değerli bir baytta duran 0x2F değerli baytlarda yolları parçalayan bir fonksiyona sahipti . namei()Unix / Linux / BSD çekirdeğinin bir parçası olduğu için, istisnai bayt değerlerinin uygulandığı yerdir.

Şu ana kadar, karakterlerden değil bayt değerlerinden bahsettim. namei()baytlarda herhangi bir karakter anlamını zorlamaz. Bu ls, dosya adlarını bayt değerlerine veya karakter değerlerine göre sıralayabilecek kullanıcı düzeyindeki programlara bağlıdır . xtermkarakter kodlamasına göre dosya adları için hangi piksellerin aydınlatılacağına karar verir. xtermUTF-8 kodlu dosya adınız olduğunu söylemezseniz , çağırdığınızda çok saçma sapan şeyler görürsünüz. Eğer vimUTF-8 (ya da her türlü UTF-16, UTF-32) kodlamaları algılamak için derlenmiş değildir UTF-8 kodlu karakterleri içeren bir "metin dosyasını" açtığınızda, anlamsız bir sürü göreceksiniz.


Doğru, namei()1986 civarında terk edildi. Daha yeni UNIX sistemleri lookuppn()VFS tabanlı.
schily

17

Mesele şu ki, çekirdek, uygulamaların bir dosya adı olarak verilen verileri nasıl yorumladığını bir bit umursamıyor.

Sadece UTF-16 dizeleriyle ilgilenen bir C uygulamam olduğunu düşünelim. Düzgün bir şekilde yapılandırılmış bir giriş yöntemi ile ∯ sembolünü (Unicode 0x222F) "Farklı Kaydet" komut istemine / iletişim kutusuna giriyorum.

Uygulama herhangi bir çeviri yapmaz ve düz eski bir C string ( char*) 'e, fopenyazma modunda, çekirdeğin ∯ görmeyeceğini, hatta hayal etmeye çalışacağını gönderirse. charDeğerleri ile birbiri ardına iki saniye görecek 0x22 0x2F(8bit karakter varsayalım ve C kütüphanesinde huni yokmuş gibi ).
Bu, çekirdek açısından, geçerli bir char ( ") ve ardından /(ASCII 0x2F) olur. fopendönecektir EISDIR(yani "bir dizine benzeyen ve yazma modunu istediniz!").
Eğer ∮ (Unicode 0x222E) girmiş olsaydım , çekirdek iki iyi karakter görecekti ve ASCII konuşan bir uygulamada görüldüğü gibi adlandırılacak bir dosya yaratmıştı "..

aUygulamaya bir dosya adı olarak girmiş olsaydım ve uygulama UTF-16'da çekirdeğe geçerse, çekirdek okurdu 0x00 0x61ve aslında zaten olduğu gibi dizeyi sonlandırdığı için 0x61bunu 0x00bile düşünmezdi. endişeli. Hata mesajı, boş bir dosya adıyla aynı olacaktır ( ENOENTinanıyorum).

Bu yüzden çekirdek gerçekten de verileri blob olarak alıyor. Bu bir chars akışı . Seçtiğiniz kullanıcı alanı kodlamanızdaki geçersiz "karakterler" , bloblarında (çekirdeğe iletilen ikili gösterimi) 0x00veya 0x2F("boş" ve /) oluşturan karakterlerdir.


Seni haklı çıkarırsam, geçersiz karakterler diye bir şey yoktur. Sadece geçersiz bayt dizileri var. Ve değerler çekirdekte kodlanmış 0x00ve 0x2Fzor. Bunun anlamı, dizinlerin a ile değil , kullanılan kodlamada /hangi karakterle eşleştirileceğidir 0x2F.
Marco,

Evet, bu şekilde görmek istersen fikir budur. (Ancak bu yanlış olabilir. Bir çekirdeğin /0x2F olmayan bir "yerel kodlama" olabilir chars- aslında 8 bit kullanmayabilir .) "Geleneksel" dir ayırıcısı /. Bu, 8 bitlik bayt ASCII'deki (örneğin, EBCDIC değil) sistemlerdeki 0x27'dir.
Mat,

UTF-16BE'yi varsayıyorsunuz, oysa UTF-16LE'de U + 0061 (boş sonlandırılmış) adizeyle sonuçlanacak .
Incnis Mrsi 12:15

4

Unix tasarlandıktan sonra baytlarla karakterlerin ayrılması büyük ölçüde gerçekleşti. Tasarlandığı zaman kelimelerin kullanımı sadece 8 (ya da 6 ya da 9) bitin nasıl yorumlandığına dair bir şeyler aktarıyordu, ama kelime kodlamalarından söz edilmedi.

Dosya adları, bayt dizileridir. 0x2f "/" dışında herhangi bir bayta izin verilir. 0x00 içeren bir bayt, bir string terminator olarak kullanılmasından dolayı çekirdeğe bile ulaşamamaktadır. Bir uygulama, bayt dizisini seçtiği kodlamaya göre yorumlayabilir. Bu karışıklık geliyorsa sanırım.

Http://www.gtk.org/api/2.6/glib/glib-Character-Set-Conversion.html adresinde yararlı bulabileceğiniz daha fazla bilgi bulunmaktadır .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.