มีอัลกอริทึมในการตัดสินใจว่า symlink วนซ้ำหรือไม่


16

ระบบ Unix มักจะผิดพลาดหากพวกเขาเผชิญกับเส้นทางที่มีการวนรอบ symlink หรือเพียงแค่ symlink มากเกินไปเพราะพวกเขามีข้อ จำกัด จำนวน symlink พวกเขาจะเข้าไปสำรวจในเส้นทางเดียว แต่มีวิธีการตัดสินใจจริง ๆ ว่าเส้นทางที่กำหนดให้แก้ไขบางสิ่งบางอย่างหรือมีการวนรอบแม้ว่ามันจะมีการเชื่อมโยงมากขึ้นกว่า Unix ยินดีที่จะปฏิบัติตาม? หรือนี่เป็นปัญหาที่ไม่สามารถตัดสินใจได้อย่างเป็นทางการ? และหากสามารถตัดสินใจได้จะสามารถตัดสินใจได้ในเวลา / หน่วยความจำที่สมเหตุสมผล (เช่นโดยไม่ต้องไปที่ไฟล์ทั้งหมดในระบบไฟล์)?

ตัวอย่างบางส่วน:

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

แก้ไข :

เพื่อความกระจ่างแจ้งฉันไม่ได้ถามเกี่ยวกับการค้นหาลูปในระบบไฟล์ฉันกำลังถามเกี่ยวกับอัลกอริทึมการตัดสินใจที่ตัดสินใจเลือกพา ธ ที่กำหนดไม่ว่าจะแก้ไขเป็นไฟล์ / ไดเรกทอรีที่ชัดเจนหรือไม่แก้ไขเลย ตัวอย่างเช่นในระบบต่อไปนี้มีการวนรอบ แต่เส้นทางที่กำหนดยังคงแก้ไขได้ดี:

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

ต้นไม้ไดเรกทอรีนี้อย่างชัดเจนมีวงจร แต่เส้นทางที่ยังคงปรับให้แก้ไขa/b/b/b/b/b/a


เครื่องมือบรรทัดคำสั่งreadlink ...พูดถึงสถานการณ์ข้างต้นอย่างไร
slm

1
คุณถามว่าเราสามารถบอกได้จากชื่อพา ธ ถ้ามีลูปไหม หรือเราสามารถทำสิ่งนี้ในระบบปฏิบัติการจริงโดยใช้เครื่องมือมาตรฐานและตรวจสอบว่าส่วนประกอบต่าง ๆ ของชื่อพา ธ แก้ไขได้อย่างไร?
Mike Diehn

@MikeDiehn เห็นได้ชัดว่าไม่มีใครสามารถบอกได้จากเพียงเส้นทางถ้ามันแก้ไขได้โดยไม่ต้องดำเนินการระบบไฟล์ แต่ด้วยสภาพแวดล้อมระบบปฏิบัติการมันไม่ได้ตรงไปตรงมาที่จะแยกแยะเส้นทางที่เพียงแค่ต้องมีการเชื่อมโยงหลาย Symphony เพื่อแก้ไขจากหนึ่งที่ไม่ได้แก้ไขเลย
JanKanis

คำตอบ:


10

ฉันไม่เข้าใจสิ่งที่คุณถาม ถ้าฉันไม่รู้อะไรเลยฉันคิดว่าคุณกำลังถามว่ามีวิธีการตรวจจับสิ่งนี้หรือไม่ในขณะที่กำลังจัดการกับไฟล์ ฉันไม่เชื่อว่าเป็นไปได้

วิธีเดียวที่ฉันคิดได้คือทำการค้นหาที่คุณเริ่มมองผ่านสาขาเฉพาะในแผนผังไดเรกทอรี

ตัวอย่าง

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

5 directories, 1 file

findคำสั่งจะตรวจสอบวงนี้ แต่ไม่ได้จริงๆบอกคุณมากทั้งเกี่ยวกับเรื่องนี้

$ 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

ผมหยิบพล 15 ระดับเพื่อป้องกันการส่งออกใด ๆ findจะถูกแสดงโดย อย่างไรก็ตามคุณสามารถปล่อยสวิตช์นั้น ( -mindepth) หากคุณไม่สนใจเกี่ยวกับแผนผังไดเรกทอรีที่จะแสดง findคำสั่งยังคงตรวจพบวงและหยุด:

$ 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

อนึ่งหากคุณต้องการแทนที่ค่าเริ่มต้นMAXSYMLINKSซึ่งเห็นได้ชัดว่า 40 บน Linux (เคอร์เนลรุ่น 3.x ที่ใหม่กว่า) คุณสามารถเห็นคำถาม & คำตอบ U & L นี้: คุณจะเพิ่ม MAXSYMLINKSอย่างไร

การใช้คำสั่ง symlinks

มีเครื่องมือที่ผู้ดูแลไซต์ FTP สามารถใช้เรียกsymlinksซึ่งจะช่วยเปิดเผยปัญหาเกี่ยวกับเครื่องมือที่มีความยาวหรือต้นไม้ห้อยต่องแต่งที่เกิดจากลิงก์สัญลักษณ์

ในบางกรณีsymlinksสามารถใช้เครื่องมือเพื่อลบลิงก์ที่ละเมิดได้เช่นกัน

ตัวอย่าง

$ 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

ห้องสมุด glibc ดูเหมือนจะเสนอฟังก์ชั่น C บางอย่างเกี่ยวกับเรื่องนี้ แต่ฉันไม่รู้บทบาทของพวกเขาทั้งหมดหรือวิธีการใช้งานจริง ดังนั้นฉันสามารถชี้ให้พวกคุณเห็นเท่านั้น

หน้าชายคนนั้นแสดงให้เห็นถึงความหมายฟังก์ชั่นสำหรับการทำงานที่เรียกว่าman symlink symlink()คำอธิบายเป็นดังนี้:

symlink () สร้างลิงค์สัญลักษณ์ชื่อ newpath ซึ่งมีสตริง oldpath

หนึ่งในข้อผิดพลาดระบุว่าฟังก์ชั่นนี้จะส่งกลับ:

ELOOP พบการเชื่อมโยงสัญลักษณ์มากเกินไปในการแก้ไข newpath

ฉันจะนำคุณไปยังหน้า man man path_resolutionซึ่งอธิบายว่า Unix กำหนดพา ธ ไปยังรายการต่างๆในดิสก์ได้อย่างไร โดยเฉพาะย่อหน้านี้

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").

ถ้าเป็นไปได้ฉันต้องการวิธีตรวจจับลูป symlink เมื่อกำหนดพา ธ เดียวและแก้ไข symlink ด้วยตนเองในโปรแกรมแทนที่จะปล่อยให้ระบบปฏิบัติการทำ แต่ฉันสงสัยว่ามันเป็นไปได้หรือไม่ โซลูชันการค้นหาดูน่าสนใจ แต่คุณมีความคิด / วิธี / ค้นหาตรวจจับลูป symlink และถ้าวิธีการที่ใช้นั้นสมบูรณ์ (เช่นตรวจจับลูปที่เป็นไปได้ทั้งหมดและไม่ได้ระบุเส้นทางที่ไม่วนลูป)
JanKanis

@Somejan - ดูอัปเดตของฉันในกลุ่ม A. แจ้งให้เราทราบหากเหมาะสม
slm

5

ตกลงหลังจากที่คิดเพิ่มเติมฉันคิดว่าฉันมีทางออกที่ชัดเจน

ข้อมูลเชิงลึกที่สำคัญคือหากทุกลิงก์ที่เป็นส่วนหนึ่งของเส้นทางแก้ไขบางสิ่งบางอย่างแล้วเส้นทางทั้งหมดจะได้รับการแก้ไข หรือวิธีอื่น ๆ หากเส้นทางไม่สามารถแก้ไขได้จะต้องมี symlink เฉพาะที่ต้องผ่านการสำรวจที่ไม่สามารถแก้ไขได้

ในขณะที่คิดเกี่ยวกับปัญหานี้ก่อนหน้านี้ฉันใช้อัลกอริทึมที่สำรวจองค์ประกอบของเส้นทางที่เริ่มต้นจากรูทและเมื่อพบ symlink มันจะแทนที่องค์ประกอบพา ธ นั้นด้วยเนื้อหาของ symlink จากนั้นทำการสำรวจต่อไป เนื่องจากวิธีนี้ไม่สามารถจำ symlink ใดได้ในขณะนี้จึงไม่สามารถตรวจพบเมื่ออยู่ในลูปที่ไม่ได้แก้ไข

หากอัลกอริทึมติดตามว่า symlink กำลังแก้ไขอยู่ (หรือ symlink ใดในกรณีที่เกิดการเชื่อมโยงซ้ำ) มันสามารถตรวจสอบได้ว่ามันกำลังพยายามแก้ไขลิงก์อีกครั้งซ้ำซึ่งมันยังไม่ว่างอยู่

ขั้นตอนวิธีการ:

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

แก้ไข :

ฉันมีการใช้งานนี้ในหลามที่ https://bitbucket.org/JanKanis/python-inotify/src/853ed903e870cbfa283e6ce7a5e41aeffe16d4e7/inotify/pathresolver.py?at=pathwatcher


3

Python มีฟังก์ชั่นที่เรียกว่า networkx.simple_ ก็ตาม () ที่สามารถใช้สำหรับสิ่งนี้ แต่ใช่มันจะต้องอ่านไฟล์ทุกไฟล์ในระบบ

>>> 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']]

ฉันคิดเกี่ยวกับการใช้อัลกอริทึมกราฟบางชนิด แต่ฉันไม่แน่ใจว่าแผนผังไดเรกทอรีที่มี symlink สามารถแสดงได้อย่างเพียงพอในกราฟอย่างง่ายหรือไม่ ในไดเรกทอรีต้นไม้ abc โดยที่ c คือ symlink ถึง .. , มีลูป แต่พา ธ เช่น a / b / c / b / c / b ยังคงแก้ปัญหาได้เนื่องจากพวกมันทำตามลูปจำนวน จำกัด และไม่ คอยวนซ้ำ
JanKanis

@Somejan: namespace ของระบบแฟ้มคือกราฟและชื่อไฟล์เป็นเส้นทางที่เลือกไว้เหนือกราฟนั้น
ninjalj

@ninjalj: ใช่ระบบไฟล์เป็นกราฟ แต่ฉันไม่คิดว่าชื่อไฟล์เป็นเพียงเส้นทางผ่านกราฟนั้น ชื่อไฟล์สามารถมองเห็นเป็นชุดของคำแนะนำเกี่ยวกับวิธีการสำรวจกราฟ แม้ว่ากราฟจะมีวัฏจักรที่ไม่ได้หมายความว่าชื่อไฟล์ที่ตามมานั้นจะไม่สามารถแก้ไขได้ แต่ให้ดูตัวอย่างของฉันในความคิดเห็นก่อนหน้า
JanKanis

3

บนระบบที่นิ่ง (เช่นเมื่อไม่มีการเปลี่ยนแปลง) ใช่มีอัลกอริทึม มีจำนวนลิงก์สัญลักษณ์ จำกัด ดังนั้นพวกเขาจึงประกอบเป็นกราฟ จำกัด และการตรวจสอบวงจรเป็นกระบวนการที่สมบูรณ์

บนระบบจริงไม่มีวิธีตรวจสอบรอบเนื่องจากลิงก์สัญลักษณ์สามารถเปลี่ยนแปลงได้ในขณะที่เครื่องตรวจจับรอบทำงาน การอ่านลิงก์สัญลักษณ์แต่ละรายการเป็นอะตอมมิก แต่การติดตามลิงก์สัญลักษณ์ไม่ใช่ หากมีบาง symlink เปลี่ยนแปลงอยู่ในขณะที่เคอร์เนลกำลังทำการสำรวจเส้นทางมันอาจสิ้นสุดบนเส้นทางที่ไม่มีที่สิ้นสุดที่เกี่ยวข้องกับการเชื่อมโยงที่แตกต่างกัน


มีวิธีที่จะลดการเปลี่ยนแปลงเหล่านั้นเพื่อนำมาซึ่งความแม่นยำสูงถึง 98-99% คุณสามารถให้ความสนใจกับการประทับเวลาในไฟล์และฉันจะไม่แนะนำตามลิงค์จริง เนื่องจากเป็นการเรียกซ้ำจากรูทจึงจะหาไดเร็กตอรี่จริงในภายหลัง
Back2Basics

1
@ Back2Basics ตัวเลขเหล่านี้ไร้ความหมายอย่างสมบูรณ์ นี่คือส่วนต่อประสานเคอร์เนล ถ้ามันไม่ทำงานตลอดเวลามันไม่ทำงานระยะเวลา
Gilles 'หยุดความชั่วร้าย'

2

ใกล้ที่สุดเท่าที่ฉันสามารถบอกได้จากการดูแหล่งที่มาของเคอร์เนล Linux ในปัจจุบันเคอร์เนลทั้งหมดจะเก็บจำนวนลิงก์ที่มันติดตามอยู่และมันจะผิดพลาดถ้ามันใหญ่กว่าจำนวนมาก ดูบรรทัด 1330 ใน namei.cสำหรับความคิดเห็นและnested_symlink()ฟังก์ชั่น แมโคร ELOOP (หมายเลขข้อผิดพลาดส่งคืนจากread(2)เรียกของระบบสำหรับสถานการณ์นี้) แสดงขึ้นในหลาย ๆ ตำแหน่งในไฟล์นั้นดังนั้นจึงอาจไม่ง่ายเหมือนการนับลิงก์ตาม แต่นั่นเป็นสิ่งที่ดูเหมือนว่า

มีจำนวนของขั้นตอนวิธีการหา "รอบ" ในรายการที่เชื่อมโยง ( วิธีการตรวจสอบวงจรของฟลอยด์ ) หรือกราฟระบุทิศทาง ไม่ชัดเจนสำหรับฉันว่าคุณต้องทำอะไรในการตรวจสอบ "ลูป" หรือ "รอบ" ที่แท้จริงในเส้นทางใดเส้นทางหนึ่ง ไม่ว่าในกรณีใดอัลกอริทึมอาจใช้เวลานานในการรันดังนั้นฉันเดาว่าการนับจำนวนลิงก์สัญลักษณ์ที่ตามมาจะทำให้คุณ 90% ของเส้นทางสู่เป้าหมายของคุณ


สำหรับการใช้งานจริงเพียงแค่นับจำนวนลิงก์ที่ไปมานั้นใช้ได้โดยเฉพาะอย่างยิ่งเนื่องจากเป็นสิ่งที่เคอร์เนลทำดังนั้นแม้ว่าคุณจะพบเส้นทางการแก้ไขที่ถูกต้องที่มี symlink มากเกินไปคุณก็ยังไม่สามารถใช้เส้นทางนั้นได้ คือที่ไม่เกี่ยวข้องกับการแก้ปัญหาด้วยตนเอง symlinks)
JanKanis
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.