Eklenen bir dosyayı taşımak güvenli midir?


28

Satır fs.appendFileeklemek için kullanılan bir node.js işlemim var file.log. Sadece her hat için yaklaşık 40 karakterlik tam hatlar eklenir; örneğin fs.appendFile("start-end"), aramalar benzer fs.appendFile("start-")ve 2 gibi değildir fs.appendFile("end"). Bu dosyayı file2.logtaşırsam, hiçbir satırın kaybolmadığından veya kısmen kopyalanmadığından emin olabilir miyim?

Yanıtlar:


36

Dosyayı dosya sistemi sınırları boyunca geçirmediğiniz sürece, işlem güvenli olmalıdır. Bu, mekanizma nedeniyle, “hareket etme” işleminin gerçekte nasıl yapıldığına bağlıdır.

Eğer mvaynı dosya sisteminde bir dosya, dosyanın gerçekten dokundu değil, yalnızca dosya sistemi kayıt değiştirilir.

$ mv foo bar

aslında böyle bir şey yapar

$ ln foo bar
$ rm foo

Bu yaratacak sert dosyası (aslında inode dosya sistemi girişi ile işaret) bağlantısını (ikinci dizin girdisi) fooadında barve kaldırmak foogirişi. Şimdi kaldırırken foo, fooinode'a işaret eden ikinci bir dosya sistemi girişi var , eski girişi fookaldırmak aslında inode'a ait herhangi bir bloğu kaldırmıyor.

Açık dosya tanıtıcısı, dosya sistemi girişini değil, dosya inode'unu işaret ettiğinden, programınız yine de dosyaya ekler.

Not: Programınız yazarlar arasındaki dosyayı kapatır ve yeniden açarsa , eski dosya sistemi girişi ile oluşturulmuş yeni bir dosyaya sahip olursunuz !

Çapraz dosya sistemi hamleleri:

Dosyayı dosya sistemi sınırları boyunca taşırsanız, işler çirkinleşir. Bu durumda, dosyanızın tutarlı kalmasını garanti edemezsiniz, çünkü mvaslında

  • hedef dosya sisteminde yeni bir dosya yarat
  • eski dosyanın içeriğini yeni dosyaya kopyala
  • eski dosyayı kaldır

veya

$ cp /path/to/foo /path/to/bar
$ rm /path/to/foo

Resp.

$ touch /path/to/bar
$ cat < /path/to/foo > /path/to/bar
$ rm /path/to/foo

Uygulamanızın yazılması sırasında kopyalamanın dosyanın sonuna ulaşıp ulaşmadığına bağlı olarak, yeni dosyada satırın yalnızca yarısına sahip olabilirsiniz.

Ayrıca, uygulamanız eski dosyayı kapatıp yeniden açmazsa, silinmiş gibi görünse bile eski dosyaya yazmaya devam eder: çekirdek, hangi dosyaların açık olduğunu ve dosya sistemi girişini silecek olsa da uygulamanızın açık dosya tanıtıcısını kapatana kadar eski dosyanın inode ve ilgili bloklarını silmez.


3
Bilginize, Unix'in ilk sürümlerinde rename()sistem çağrısı yoktu . Yani mvaslında orjinal versiyonu link()sabit bağlantıyı oluşturmak için çağrı yaptım , ardından unlink()orjinal ismi kaldırdık. rename()Bunu atomik olarak çekirdeğe uygulamak için FreeBSD'ye ilave edildi.
Barmar

Üzgünüm ama ne file-system borders?
laike9m

1
@ laike9m - Dosya sistemi sınırları, basit bir dosya sisteminin bir disk sürücüsü gibi bir bellek aygıtındaki bir bölümde bulunması gerektiği anlamına gelir. Dosya sistemindeki bir dosyayı yeniden adlandırırsanız, değişiklik yapan tek şey bir dizin girişindeki adıdır. Hala aynı inode'a sahip - eğer başlangıçta inode'lara dayanan bir dosya sistemindeyse - çoğu Linux dosya sisteminde olduğu gibi. Ancak, dosyayı başka bir dosya sistemine taşırsanız, gerçek verilerin taşınması gerekir ve dosya yeni dosya sisteminden yeni bir inode alır. Bu, bu gerçekleştiğinde devam etmekte olan dosyadaki işlemleri engeller.
Joe

9

Node.js kullandığınızı söylediğinizden, dosyaları yeniden adlandırmak için fs.rename()(veya fs.renameSync()) kullanacağınızı farz ediyorum . Bu node.js yöntemi, dosyaya herhangi bir şekilde dokunmayan, ancak dosya sisteminde listelenen adını yalnızca değiştiren, yeniden adlandır (2) sistem çağrısını kullanması için belgelenmiştir :

" Yeniden adlandırma () gerekirse dizinleri arasında taşıyarak, bir dosyayı yeniden adlandırır. Dosyaya Başka sabit bağlantıları (kullanılarak oluşturulan olarak bağlantı (2) ) etkilenmez. Açık dosya tanımlayıcıları oldpath da etkilenmez."

Özellikle, herhangi bir açık dosya tanımlayıcısının (programınız dosyaya yazmak için kullanılacağı gibi) herhangi bir açık dosya tanımlayıcısının, yeniden adlandırıldıktan sonra bile işaret etmeye devam edeceğini söyleyen son alıntıyı not edin. Bu nedenle, dosya aynı anda yazılırken yeniden adlandırılsa bile veri kaybı veya bozulma yaşanmaz.


Andreas Weise'ın cevabında belirttiği gibi, yeniden adlandırma (2) sistem çağrısı (ve böylece fs.rename()node.js'de) dosya sistemi sınırları boyunca çalışmaz. Bu nedenle, bir dosyayı farklı bir dosya sistemine bu şekilde taşımaya çalışmak basitçe başarısız olacaktır.

Unix mvkomutu, hatayı algılayarak ve bunun yerine, içeriğini yeni bir dosyaya kopyalayıp orijinali silerek dosyayı taşıyarak bu sınırlamayı gizlemeye çalışır. Ne yazık ki, bu gibi dosyaları hareketli yapar o kadar yazılırken dosya taşınır, eğer risk veri kaybını. Böylece, güvenli bir şekilde eş zamanlı olarak, sen gerektiğini yazılabilir dosyaları yeniden adlandırmak istiyorsanız değil kullanmak mv(en azından, kesinlikle emin yeni ve eski yolu aynı dosya sistemi üzerinde olduğundan yapmalıdır veya).

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.