CPH'nin hardlink ile davranışı şaşırttı


20

Hardlinks kavramını çok iyi anlıyorum ve cp--- ve hatta en son POSIX özellikleri gibi temel araçlar için adam sayfalarını birkaç kez okudum . Yine de aşağıdaki davranışı gözlemlemekten şaşırdım:

$ echo john > john
$ cp -l john paul
$ echo george > george

Bu noktada johnve paulaynı inode (ve içeriğe) sahip georgeolacak ve her iki açıdan da farklı olacaktır. Şimdi yapıyoruz:

$ cp george paul

Bu noktada beklenen georgeve paulfarklı inode'a ama aynı içeriği --- bu beklenti gerçekleşti olması --- ama aynı zamanda beklenen paulşimdi farklı bir inode numarası olması johnve için, johnhala içeriğe sahip john. İşte burada şaşırdım. Bir dosyayı hedef yola kopyalamanın paul, aynı dosyayı (aynı inode), inode'yu paylaşan diğer tüm hedef yollara kurmanın sonucu olduğu da ortaya çıkıyor paul. Bunun cpyeni bir dosya oluşturduğunu ve eski dosyanın işgal ettiği yere taşıdığını düşünüyordum paul. Bunun yerine, var olan dosyayı açmak paul, kısaltmak ve yazmakgeorgeiçeriğini mevcut dosyaya aktarın. Bu nedenle, aynı inode'a sahip "diğer" dosyalar, "içeriklerini" aynı anda günceller.

Tamam, bu sistematik bir davranış ve şimdi beklediğimi bildiğime göre, uygun şekilde nasıl çalışacağını veya bundan nasıl faydalanabileceğimi anlayabilirim. Bu davranışı belgelediğim yerde beni şaşırtan ne oldu? Daha önce baktığım belgelerde bir yerde belgelenmemişse şaşırırdım . Ama görünüşe göre kaçırdım ve şimdi bu davranışı tartışan bir kaynak bulamıyorum.

Yanıtlar:


4

İlk olarak, neden bu şekilde yapılıyor? Bunun bir nedeni tarihseldir: Unix First Edition'da böyle yapıldı .

Dosyalar çift olarak alınır; birincisi okuma için açılır, ikinci oluşturulan mod 17. Daha sonra birincisi ikincisine kopyalanır.

“Oluşturuldu” , varsa, varolan dosyayı verilen ada göre kesencreat sistem çağrısını ( e olarak ünlü olanı) ifade eder .

Ve burada 'kaynak kodunu s cpUnix İkinci Baskı (Ben birinci Edition kaynak kodunu bulamıyorum). openKaynak dosya ve creatikinci dosya için yapılan çağrıları görebilirsiniz ; ve First Edition'da yapılan bir iyileştirme olarak, ikinci dosya varolan cpbir dizinse, bu dizinde bir dosya oluşturur.

Ama sorabilirsiniz, neden o zaman böyle yapıldı? “Unix'i neden bu şekilde yaptı” cevabı neredeyse her zaman basitliktir. cpokumak için kaynağını açar ve hedefini oluşturur - ve bir dosya oluşturmaya yönelik sistem çağrısı, varolan bir dosyanın üzerine yazmak için üzerine yazarak yazar, çünkü bu, arayanın dosyanın var olup olmadığını, değil.

Şimdi, nerede belgelendiği konusunda: FreeBSD kılavuz sayfasında .

Zaten var olan her hedef dosya için, izinlere izin verilirse içeriğinin üzerine yazılır. -P seçeneği belirtilmedikçe modu, kullanıcı kimliği ve grup kimliği değişmez.

Bu ifade en azından 1990'a kadar vardı (BSD 4.3BSD olduğu zaman). Solaris 10'da benzer ifadeler var :

Target_file varsa, cp içeriğinin üzerine yazar, ancak onunla ilişkili mod (ve varsa ACL), sahibi ve grubu değiştirilmez.

Durumunuz HP-UX 10 kılavuzunda bile belirtilmiştir:

New_file, diğer bağlantıları içeren varolan bir dosyanın bağlantısıysa, varolan dosyanın üzerine yazar ve tüm bağlantıları korur.

POSIX bunu standardese koyar. Tek UNIX v2'den alıntı :

Dest_file varsa, aşağıdaki adımlar uygulanır: (…) dest_file için bir dosya tanımlayıcı, yol argümanı olarak dest_file ve O_WRONLY ve O_TRUNC'un bitsel olarak dahil edilen VEYA'sı olarak adlandırılan XSH belirtimi open () işlevine eşdeğer eylemler gerçekleştirilerek elde edilir. oflag argümanı olarak.

Alıntıladığım man sayfaları ve belirtimi, -fseçenek geçilirse ve hedef dosyayı açma / oluşturma girişimi başarısız olursa (genellikle dosyayı yazma iznine sahip olmadığından), cphedefi kaldırmaya ve yeniden dosya oluşturmaya çalıştığını belirtir . Bu, senaryonuzdaki sabit bağlantıyı kesecektir.

Bu davranışı belgelemediği için GNU coreutils el kitabına karşı bir belge hatası bildirmek isteyebilirsiniz . --preserve=linksSenaryonuzda paulbağlantının kaldırılmasına ve yeni bir dosyanın oluşturulmasına yol açacak olan açıklama bile, onsuz ne olduğunu netleştirmez --preserve=links. Bu -ftür bir açıklama, onsuz ne olduğunu ima eder, ancak bunu açıklamaz (“Bu seçenek olmadan kopyalanırken ve varolan bir hedef dosya yazmak için açılamazsa, kopya başarısız olur. Ancak, --force,…” ile).


neden "çünkü bu dosya zaten mevcut olsun ya da olmasın arayanın bir dosya adının sahipliğini almasına izin veriyor" diyorsunuz? Cp, önceden var olan bir dosyanın sahipliğini almaz.
jrw32982 Monica

@ jrw32982 Dosya meta verisi açısından sahiplik değil, dosyaya ne girdiğine karar verme anlamında sahiplik demek istedim. Bu cümleyi yeniden yazdım.
Gilles 'SO- kötü olmayı kes'

20

cphedef dosya zaten varsa hedef dosyanın üzerine yazdığı belgeler. "Üzerine yazma" nın ne anlama geldiğini ayrıntılı olarak belirtmediği konusunda haklısın, ama kesinlikle "değiştir" değil, "üzerine yazma" diyor. Bilgiçlikçi olmak istiyorsanız, "üzerine yazma" nın tam olarak ne cpolduğunu ve beklediğiniz davranışın "değiştir" olarak adlandırılacağını iddia edebilirsiniz .

Ayrıca, cpönceden var olan hedef dosyaları "değiştirecek" ise, bunun şaşırtıcı veya yanlış olarak kabul edilebileceğini, muhtemelen "üzerine yazma" dan daha fazla olabileceğini unutmayın. Örneğin:

  • Eğer cpÖnce eski dosyayı silip sonra yeni bir tane oluşturduktan sonra şaşırtıcı olacağını dosya eksik olacağını sırasında bir zaman aralığıdır, olmazdı.
  • Eğer cpilk geçici bir dosya oluşturulur ve sonra da yerine taşındı o zaman muhtemelen garip isimlerle, geçici dosyaların ara sıra fark olurdu aslında sayesinde, bu dokümante etmelidir ... ama öyle değil.
  • Eğer cpnedeniyle izinleri eski dosyayla aynı dizinde yeni bir dosya oluşturmak olamazdı o zaman bu (zaten eskisini silinmiş olduğu özellikle) talihsiz olurdu.
  • Dosya, çalışan kullanıcı tarafından sahiplenmemişse cpve çalışan kullanıcı cpolmasa root, yeni dosyanın sahibini ve izinlerini yeni dosyanınkilerle eşleştirmek imkansızdır.
  • Dosyanın cpbilmediği fantezi özel öznitelikleri varsa, bunlar kopyada kaybolur. Günümüzde cpgenişletilmiş özellikler gibi şeyleri güvenilir bir şekilde anlaması gerekiyor, ancak her zaman böyle değildi. MacOS kaynak çatalları veya uzak dosya sistemleri için temelde her şey gibi başka şeyler de var.

Sonuç olarak: şimdi cpgerçekten ne yaptığını biliyorsun . Bir daha asla şaşıracaksınız! Dürüst olmak gerekirse, sanırım aynı şey uzun yıllar önce de başıma gelmiş olabilir.


POSIX referansını kontrol etmek zorundasınız, ancak aslında BSD (en azından OSX) ve Gnu sürümlerindeki mansayfalar "üzerine yazma" konusunda çok açık değil. Bu kelime sadece seçeneklerinde yapılan yorumlar kullanılır ve . Gnu manpage özellikle bilgilendirici değil, BSD / Mac manpage en azından diyorcpcp-i-nCopy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.In the first synopsis form, the cp utility copies the contents of the source_file to the target_file.
dubiousjim

Gnu coreutils bilgi sayfası başlıyor:‘cp’ copies files (or, optionally, directories). The copy is completely independent of the original.
dubiousjim

2
POSIX 2008 standardının gözlemlenen davranışı belirttiğini görüyorum; Bir cevap ekleyeceğim.
dubiousjim

16

POSIX 2013 standardının gözlemlenen davranışı belirttiğini görüyorum . Diyor ki:

  1. Eğer source_file tipi düzenli dosyasının olduğu, aşağıdaki adımlar olacaktır:

    a. ... dest_file varsa, aşağıdaki adımlar atılacaktır:

    ben. Eğer -iseçenek etkin, cpyarar standart hataya bir istem yazmak ve standart girdiden bir satır okuyacağım. Yanıt olumlu değilse kaynak_dosyasıcp ile başka bir şey yapmaz ve kalan dosyalara devam eder.

    ii. Yol_dosyası için bir dosya tanımlayıcı, POSIX.1-2008'inopen() Sistem Arabirimleri biriminde tanımlanan fonksiyona eşdeğer eylemler gerçekleştirerek ve yol bağımsız değişkeni olarak hedef_dosyası olarak ve oflag bağımsız değişkeninin bitsel olarak dahil ORedilmesi O_WRONLYve oflag argümanı olarak elde edilir.O_TRUNC

    iii. Bir dosya tanıtıcı elde etmek girişimi başarısız olur ve varsa -fseçenek etkin, cpkarşı eylemler eşdeğer gerçekleştirerek dosyayı kaldırmak üzere harekete geçer unlink()kullanılarak denilen POSIX.1-2008 Sistem Arabirimleri hacmi tanımlanan işlevin dest_file yolu argüman olarak. Bu girişim başarılı cpolursa, adım 3b ile devam edecektir.

    ...

    d. Source_file içeriği dosya tanımlayıcısına yazılmalıdır. Herhangi bir yazma hatası, cpstandart hataya bir teşhis mesajı yazılmasına ve adım 3e'ye devam etmesine neden olacaktır .

    e. Dosya tanımlayıcı kapatılacaktır.


1
İlginç. Senin gibi, ben cpde benzer sonuçlar vereceğini mvve hedefin bir parçası olduğu herhangi bir zorlamayı kıracağımı varsaydım . Ama şimdi bunu düşündüğümde, bu özellikle unlink(2)hedefe ( cp -f) veya farklı adlandırılmış bir geçici ve daha sonra yaratması gerektiği anlamına gelir rename(2). Basit uygulama sadece dosyanın üzerine yazmak için dosyayı açmaktır, bu POSIX'in gerektirdiği şeydir. Eşdeğercat src > dest
Peter Cordes

2

“Bir dosyayı hedef yola paul kopyalamak da aynı dosyayı (aynı inode) paul'in inode'unu paylaşan diğer tüm hedef yollara da kopyalar .” Diyebilirseniz, sabit bağlantılar çok iyi. Sir McCartney'e elma verirsem Paul'e bir elma verdim ve John Lennon'un şarkı yazarı partnerine bir elma verdim. Ama üç elma vermedim; Birden fazla adı / başlığı / tanımlayıcısı olan bir kişiye bir elma verdim.

Kopyalamak Benzer şekilde, georgehiç paul, sen değil de kopyalamadan john. Bunun yerine, georgeverileri pauldizin girdisi tarafından inode gösterilen dosyaya kopyalıyorsunuz .

Adım Adım:   Ne zaman

echo john > john

yeni bir dosya oluşturdunuz ( johnbu dizinde zaten bir dosya bulunmadığını varsayarak ). Daha açık konuşmak johngerekirse, bu zaten o dizindeki adla bir dizin girişi olmadığını varsayar (çünkü, kesinlikle, dizinlerde dosya yoktur; yalnızca inode'lara işaret eden dizin girişleri). Yaptıktan sonra

cp -l john paul

veya

ln john paul

yeni bir dosya oluşturmadınız; bunun yerine, mevcut dosyanıza yeni bir ad verdiniz. Artık iki ada sahip bir dosyanız var: johnve paul. Ve dediğinde

cp george paul

o dosyanın üzerine yazıyorsunuz . İki isme sahip olması önemsizdir; muhtemelen erişemeyeceğiniz yerlerde 42 ad olabilir ve bu komut george\nverileri bu adların tümüne (yollara) kopyalamaz ; sadece verileri birden fazla ada sahip tek bir dosyaya kopyalamaktır .


1
Teşekkürler. Doğru, ben yazarken yazdıklarımın korkutmak için gereken karakterin farkındaydım: johnve paulaynı dosya için iki yol adı olarak başlıyorum. Ama kendimi ifade etmenin en kolay yolu buydu. Ben sadece doğru bir şekilde anlaşılır bir zor bağlantı kavramını (olmadan ) iki davranış dikte olduğunu sanmıyorum . cp-l
dubiousjim

Ama ürün için teşekkürler; İfadeyi açıklığa kavuşturmaya çalıştım.
dubiousjim
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.