Yanıtlar:
@Kusalananda tarafından belirtildiği gibi, genellikle eski dosyayı kaldırarak ve aynı ada sahip yeni bir dosya oluşturarak yükseltmeler yapılır. Bu aslında yeni bir inode ile yeni bir dosya oluşturacak ve sistemi eski dosyayı açık olduğu sürece serbest bırakacaktır.
Basitleştirilmiş bir örnek olarak,
rm /bin/cat
cp /new/version/of/cat /bin/cat
mantıksal olarak yeni bir dosya oluşturur ve çalışıyor olsa bile cat
çalışır. Aynı şey kütüphaneler için de geçerli. (Yukarıdaki bir örnek, gerçek dünyada bir dosyayı yükseltmenin sağlam bir yolu değildir.)
Birisi aynı ada sahip yeni bir tane oluşturmak yerine ikili dosyayı yerinde değiştirmeye çalışabilir. Bu durumda, en azından Linux aslında kullanılan bir yürütülebilir dosyada değişiklik yapılmasını önler:
window 1 # ./cat
window 2 # echo foobar > cat
-bash: cat: Text file busy
Ancak, bu dinamik olarak yüklenmiş kütüphanelerle çalışmıyor gibi görünüyor ...
libc.so.6
Test için bir kopyasını yaptım ve kullanımdayken sıfırlarla doldurdum:
window 1 /tmp/lib# LD_LIBRARY_PATH=/tmp/lib ldd ./cat
linux-vdso.so.1 (0x00007ffcfaf30000)
libc.so.6 => /tmp/lib/libc.so.6 (0x00007f1145e67000)
/lib64/ld-linux-x86-64.so.2 (0x00007f1146212000)
window 1 /tmp/lib# LD_LIBRARY_PATH=/tmp/lib ./cat
foo
foo
Segmentation fault
(Bu arada başka bir pencerede, foo
segfault öncesi,)
window 2 /tmp/lib# dd if=/dev/zero of=libc.so.6 bs=1024 count=2000
Programın kodunu etkili bir şekilde çevrimiçi düzenlediğim için, programın kendisinin buna karşı yapabileceği gerçekten hiçbir şey yok.
(Bu muhtemelen sisteme bağlı olacaktır, Debian Jessie 8.5, Linux 3.16.7-ckt25-2 + deb8u3 üzerinde test ettim. Özellikle IIRC Windows sistemleri, kullanımdaki dosyaların değiştirilmesini önleme konusunda daha da agresiftir.)
Bu yüzden cevap, yükseltmelerin genellikle herhangi bir problemden kaçınacak şekilde yapıldığı ve bunun dosya sistemi içselleri tarafından yardımcı olduğu sanırım. Ancak (Linux'ta), aslında dinamik kütüphanelerin bozulmasına karşı herhangi bir güvence yok gibi görünüyor.
install
program yaygın olarak bu tür şeyler için kullanılır. rm
Hedef dosyayı açıkça belirtmenize gerek yoktur . Ayrıca mevcut dosyanın izinlerini korur, yedekleme yapabilir, yeni bir mod ayarlayabilir vb. Örnek kullanım:install /new/version/of/cat /bin/cat
rm
+ cp
Örnek olarak ifade edildi. Ayrıca, yeni dosyanın her ikisinin de bulunmadığı kısa bir pencereden kaçınmak için yeni dosyayı atomik olarak yerine koymak akıllıca olabilir. (GNU install
bunu yapmamış gibi görünse de,
rm
), o zaman henüz silinmez. Diskte mevcut olacak ve hala açık olan tüm işlemler tarafından okunabilecektir. Yalnızca sabit bağlantı sayısı sıfıra ulaştığında VE dosya açıkken yapılan önbellek sayısı sıfıra ulaştığında silinir.
install
program özellikle güvensiz! Hedef dosyayı atomik olarak değiştirmek yerine yerine yazar. mv
(kaynak ve hedef aynı dizinde, kaynak genellikle geçici bir dosyadır) dosyaları yüklemenin tek güvenli yoludur.
strace
söylediğim gibi install
, GNU coreutils'de hedef dosyanın bağlantısını kaldırıyor ve yerine yeni bir tane kopyalıyor. Bu, dosyanın kısmi olduğu kısa bir pencere olduğu anlamına gelir. Dosyayı yeniden adlandırma ile atomik olarak yerine koymaz.
Dosyalar hala açıkken bağlantısı kaldırılırsa "düzgün bir şekilde silinmez". Kapatıldıklarında, kullandıkları disk alanı tekrar "boş" olarak kabul edilecektir. Bu, şu anda çalışan uygulamalar ve bunların paylaşılan kitaplıkları için de geçerlidir.
Başarısız olduğunu görebildiğim tek şey, bir programın dlopen()
isteğe bağlı olarak paylaşılan bir kitaplığı yüklemek için kullandığı veya programın sözlükler, tema dosyaları veya aniden kaybolan diğer dosyalar gibi isteğe bağlı diğer dosyalara erişmesi gerektiğidir.
Örneklemek gerekirse: Başka bir kabuk oturumunun vim
kurulumunu silerken vim
bir kabuk oturumunda çalıştırmak, o anda çalışan vim
oturumu "bozmaz" veya sonlandırmaz . Ancak, örneğin vim
kurulumunda dosyaları açmayı gerektiren yazım denetimi gibi bazı şeyler başarısız olmaya başlayacaktır .
ln -sf
çünkü, kütüphaneler üzerinde takas zaman-f
izin bunu hiç "kırık" olmadan yenisi ile sembolik bağın "yazma" mevcut hedef, (hiç bir eğer aksinerm
ardından aln -s
). Komuttan önce, library.so eski sürüme işaret etti, örn. library.so.4 ... komutundan sonra, sadece işaret library.so.5 yerine (ya da herneyse) - hiç olmadan değil , geçerli bir kütüphaneye işaret.