Bir sembolik bağın döngüye girip girmeyeceğine karar verecek bir algoritma var mı?


16

Unix sistemleri genellikle yalnızca bir symlink döngüsü veya çok fazla sembol içeren bir yolla karşı karşıya kaldıklarında hata yaparlar, çünkü tek bir yol aramasında geçecekleri sembol bağlantılarının sayısında bir sınıra sahiptirler. Ancak, bir unix'in izlemeye istekli olduğundan daha fazla bağlantı içeriyor olsa bile, belirli bir yolun bir şeye çözülüp çözülmediğine veya bir döngü içerdiğine karar vermenin bir yolu var mı? Yoksa bu resmi olarak kararsız bir sorun mu? Ve eğer karar verilebiliyorsa, makul bir süre / bellekte karar verilebilir mi (örneğin bir dosya sistemindeki tüm dosyaları ziyaret etmek zorunda kalmadan)?

Bazı örnekler:

a/b/c/d
where a/b is a symlink to ../e
and e is a symlink to f
and f is a symlink to a/b

a/b/c/d
where a/b/c is a symlink to ../c

a/b/c/d
where a/b/c is a symlink to ../c/d

a/b/c/d
where a/b/c is a symlink to /a/b/e
where a/b/e is a symlink to /a/b/f
where a/b/f is a symlink to /a/b/g

Düzenle :

Açıklığa kavuşturmak için, dosya sisteminde döngüler bulma hakkında sormuyorum, belirli bir yol / dizine çözülüp çözülmediğine veya hiç çözülüp çözülmediğine karar veren bir karar algoritması soruyorum. Örneğin, aşağıdaki sistemde bir döngü vardır, ancak verilen yol yine de iyi bir şekilde çözülür:

/ -- a -- b
where b is a symlink to /a

Bu dizin ağacının açıkça bir döngüsü vardır, ancak yol a/b/b/b/b/bhala iyi şekilde çözülür /a.


Komut satırı aracı readlink ...yukarıdaki durumlar hakkında ne diyor?
slm

1
Döngüler olup olmadığını sadece yol adından söyleyip söyleyemeyeceğimizi mi soruyorsunuz? Yoksa standart araçları kullanarak ve yol adının çeşitli bileşenlerinin neyi çözdüğünü kontrol ederek gerçek bir işletim sisteminde yapabilir miyiz?
Mike Diehn

@MikeDiehn Belli ki dosya sistemi işlemleri yapmadan çözümlenirse sadece bir yoldan söyleyemez. Ama aynı zamanda bir işletim sistemi ortamında, hiç çözülmeyen bir yoldan çok sayıda sembolik bağın geçmesini gerektiren bir yolu ayırt etmek kolay değildir.
JanKanis

Yanıtlar:


10

Ne istediğini tam olarak anlamıyorum. Daha iyi bilmiyorsam, bir dosya ile uğraşırken bunu tespit etmenin bir yolu olup olmadığını sorduğunuzu düşünüyorum. Bunun mümkün olduğuna inanmıyorum.

Anlayabildiğim tek yöntem, özellikle dizin ağacındaki belirli bir dalı aramaya başladığınız bir bulma işlemi yapmaktır.

Misal

$ tree 
.
`-- a
    `-- b
        |-- c
        |   `-- d
        |       `-- e -> ../../../../a/b
        `-- e -> e

5 directories, 1 file

findKomut bu döngü algılar ama gerçekten size bu konuda bir sürü haber.

$ find -L . -mindepth 15
find: File system loop detected; `./a/b/c/d/e' is part of the same file system loop as `./a/b'.
find: `./a/b/e': Too many levels of symbolic links

Tarafından görüntülenen herhangi bir çıkışı engellemek için keyfi olarak 15 seviye seçtim find. Bununla birlikte -mindepth, görüntülenen dizin ağacını önemsemiyorsanız bu switch'i ( ) bırakabilirsiniz . findKomut hala döngü ve durur algılar:

$ find -L . 
.
./a
./a/b
./a/b/c
./a/b/c/d
find: File system loop detected; `./a/b/c/d/e' is part of the same file system loop as `./a/b'.
find: `./a/b/e': Too many levels of symbolic links

Bu arada, MAXSYMLINKSLinux'ta görünüşte 40 olan varsayılanı geçersiz kılmak istiyorsanız (çekirdeğin yeni 3.x sürümleri) şu U&L Soru-Cevap başlıklı başlığı görebilirsiniz: MAXSYMLINKS'i nasıl artırırsınız ?

Symlinks komutunu kullanma

FTP site bakımcılarının kullanabileceği bir araç var, symlinksbu da sembolik bağlantıların neden olduğu araç uzun veya sarkan ağaçlarla ilgili sorunları ortaya çıkarmaya yardımcı olacak.

Belirli durumlarda symlinksaraç, rahatsız edici bağlantıları silmek için de kullanılabilir.

Misal

$ symlinks -srv a
lengthy:  /home/saml/tst/99159/a/b/c/d/e -> ../../../../a/b
dangling: /home/saml/tst/99159/a/b/e -> e

Glibc Kütüphanesi

Glibc kütüphanesi bu konuda bazı C işlevleri sunuyor gibi görünüyor, ancak rollerini ya da gerçekte nasıl kullanacaklarını bilmiyorum. Sadece onları size gösterebilirim.

Man sayfası, man symlinkadlı bir fonksiyonun fonksiyon tanımını gösterir symlink(). Açıklama şu şekilde:

symlink (), oldpath dizesini içeren newpath adında sembolik bir bağlantı oluşturur.

Hatalardan biri, bu işlevin döndürdüğünü belirtir:

ELOOP Yeni yolun çözümünde çok fazla sembolik bağlantıyla karşılaşıldı.

Ayrıca sizi man path_resolutionUnix'in diskteki öğelere giden yolları nasıl belirlediğini tartışan man sayfasına yönlendireceğim . Özellikle bu paragraf.

If  the component is found and is a symbolic link (symlink), we first 
resolve this symbolic link (with the current lookup directory as starting 
lookup directory).  Upon error, that error is returned.  If the result is 
not a directory, an ENOTDIR error is returned.  If the resolution of the 
symlink is successful and returns a directory, we set the current lookup
directory to that directory, and go to the next component.  Note that the 
resolution process here involves recursion.  In order  to  protect  the 
kernel against stack overflow, and also to protect against denial of 
service, there are limits on the maximum recursion depth, and on the maximum 
number of symbolic links followed.  An ELOOP error is returned  when  the
maximum is exceeded ("Too many levels of symbolic links").

Mümkünse, tek bir yol verildiğinde bir sembolik bağlantı döngüsünü algılamanın ve sembolik bağlantıları işletim sisteminin yapmasına izin vermek yerine bir programda manuel olarak çözmenin bir yolunu istiyorum. Ama bunun mümkün olup olmadığını merak ediyorum. Bulma çözümü ilginç görünüyor, ancak herhangi bir fikriniz var / nasıl / find symlink döngülerini tespit ediyor ve kullandığı yöntem tamamlanmışsa (yani tüm olası döngüleri algılar ve döngü olmayan yolları yanlış tanımlamaz)?
JanKanis

@Somejan - A. için güncellemelerime bakın. Bunun mantıklı olup olmadığını bana bildirin.
slm

5

Tamam, biraz düşündükten sonra net bir çözüm bulduğumu düşünüyorum.

Kritik görüş, bir yolun parçası olan her bağlantı bir şeye çözümlenirse, tüm yolun çözülmesidir. Ya da başka bir yol, eğer bir yol çözülmezse, çözülmeyen çapraz geçiş gerektiren belirli bir sembolik bağlantı olmalıdır.

Bu sorunu daha önce düşünürken, kökten başlayarak bir yolun öğelerini geçen bir algoritma kullanıyordum ve bir sembolik bağlantıyla karşılaştığında, bu yol öğesini semboliklik içeriğiyle değiştirdi ve sonra da devam etmeye devam ettim. Bu yaklaşım şu anda hangi symlink'i çözdüğünü hatırlamadığından, çözülmeyen bir döngüde olduğunu algılayamaz.

Algoritma şu anda hangi symlink'i çözdüğünü (veya özyinelemeli bağlantılar durumunda hangi sembolik bağlantıları) takip ederse, bir bağlantıyı tekrar tekrar çözmeyle meşgul olduğu bir bağlantıyı tekrar tekrar çözmeye çalışıp çalışmadığını tespit edebilir.

Algoritma:

initialize `location` to the current working directory
initialize `link_contents` to the path we want to resolve
initialize `active_symlinks` to the empty set

def resolve_symlink(location, link_contents, active_symlinks) :
    loop forever:
        next_location = location / [first element of link_contents]
        see if next_location is a symlink.
        if so:
            if next_location in active_symlinks: abort, we have a loop
            location = resolve_symlink(location, readlink(next_location), active_symlinks ∪ {next_location})
        else:
            location = next_location
        strip first element of link_contents
        if link_contents is empty: 
            return location

düzenleme :

Bunu python'da https://bitbucket.org/JanKanis/python-inotify/src/853ed903e870cbfa283e6ce7a5e41aeffe16d4e7/inotify/pathresolver.py?at=pathwatcher adresinde çalışan bir uygulamam var .


3

Python, bunun için kullanılabilen networkx.simple_cycles () adında bir işleve sahiptir. Ancak evet, sistemdeki her dosyayı okuması gerekir.

>>> import networkx as nx
>>> G = nx.DiGraph()
>>> G.add_edge('A', 'B')
>>> G.add_edge('B', 'C')
>>> G.add_edge('C', 'D')
>>> G.add_edge('C', 'A')
>>> nx.simple_cycles(G)
[['A', 'B', 'C', 'A']]

Ayrıca bir tür grafik algoritması kullanmayı düşündüm, ancak sembolik bir dizin ağacının basit bir grafikte yeterince temsil edilip edilemeyeceğinden emin değilim. C'nin .. için bir sembolik olduğu abc dizin ağacında, bir döngü vardır, ancak / b / c / b / c / b gibi yollar, döngüyü yalnızca sınırlı sayıda takip ettikleri ve çözmedikleri için hala çözülür dönmeye devam et.
JanKanis

@Somejan: bir dosya sistemi ad olduğu bir grafiktir, ve bir dosya bu grafiğin üzerine seçilen bir yoldur.
ninjalj

@ninjalj: Evet bir dosya sistemi bir grafiktir, ancak bir dosya adı olduğunu sanmıyorum sadece o grafiğin üzerine bir yolu. Dosya adı, grafiğin nasıl dolaşılacağı hakkında bir dizi talimat olarak görülebilir. Grafik, bu döngüyü izleyen bir dosya adının mutlaka çözümlenmediği anlamına gelmeyen döngüler içeriyor olsa bile, önceki yorumumdaki örneğime bakın.
JanKanis

3

Hareketsiz bir sistemde (yani hiçbir değişiklik olmadığında), evet, bir algoritma vardır. Sonlu sayıda sembolik bağ vardır, bu nedenle sonlu bir grafik oluştururlar ve döngüleri tespit etmek son derece kolaydır.

Canlı bir sistemde, döngüleri tespit etmenin bir yolu yoktur, çünkü döngü dedektörü çalışırken sembolik bağlantılar değişebilir. Her sembolik bağın okunması atomiktir, ancak sembolik bir bağın izlenmesi değildir. Çekirdek çapraz geçiş yaparken bazı semboller değişmeye devam ederse, farklı bağlantılar içeren sonsuz bir yolla sonuçlanabilir.


% 98-99'a varan doğruluk sağlamak için bu değişiklikleri hafifletmenin yolları vardır. Dosyalardaki zaman damgalarına dikkat edebilirsiniz ve aslında bağlantıları izlemenizi önermem. Kökten özyinelemeli olduğundan, gerçek dizini daha sonra bulur.
Back2Basics

1
@ Back2Basics Bu sayılar tamamen anlamsız. Bu bir çekirdek arayüzüdür. Her zaman işe yaramazsa, işe yaramaz, nokta.
Gilles 'SO- kötü olmayı kes

2

Mevcut Linux çekirdek kaynaklarına bakarken anlayabildiğim kadarıyla, çekirdeğin yaptığı, kaç bağlantı izlendiğinin bir sayısını tutmak ve bunun bir sayıdan daha büyük olması durumunda hata veriyor. Yorum ve işlev için namei.c dosyasındaki 1330 satırına bakın nested_symlink(). ELOOP makrosu ( read(2)bu durum için bir sistem çağrısından döndürülen hata numarası ) bu dosyadaki birkaç yerde görünür, bu nedenle takip edilen bağlantıların sayılması kadar basit olmayabilir, ancak neye benzediğinden emin olabilirsiniz.

Bağlantılı listelerde ( Floyd'un döngü algılama algoritması ) veya yönlendirilmiş grafiklerde "döngüleri" bulmak için bir dizi algoritma vardır . Belirli bir yolda gerçek bir "döngü" veya "döngü" tespit etmek için hangisini yapmanız gerektiği açık değildir. Her durumda, algoritmaların çalışması uzun zaman alabilir, bu yüzden sadece takip edilen sembolik bağlantıların sayısını saymanın hedefinize giden yolun% 90'ını aldığını tahmin ediyorum.


Pratik kullanımlar için, sadece çapraz bağlantıların sayılması iyidir, özellikle çekirdeğin yaptığı budur, bu nedenle çok fazla sembolik bağlantısı olan doğru bir çözüm yolu ile karşılaşsanız bile, bu yolu pratik bir şey için kullanamazsınız ( yani, sembolik bağlantıları manuel olarak çözmeyi içermez)
JanKanis
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.