Perché i collegamenti fisici alle directory non sono consentiti in UNIX / Linux?


130

Ho letto nei libri di testo che Unix / Linux non consente collegamenti rigidi alle directory ma consente collegamenti soft. È perché, quando abbiamo cicli e se creiamo collegamenti fissi e dopo qualche tempo eliminiamo il file originale, indicherà un valore di garbage?

Se i cicli fossero l'unico motivo dietro non consentire collegamenti fissi, allora perché sono consentiti i collegamenti soft alle directory?


2
Dove dovrebbe ..puntare a? Soprattutto dopo aver rimosso il collegamento reale a questa directory, nella directory indicata da ..? Deve puntare da qualche parte.
Thorbjørn Ravn Andersen,

2
..non ha bisogno di esistere fisicamente su nessuna unità. È comunque compito del sistema operativo tenere traccia della directory di lavoro corrente, quindi dovrebbe essere relativamente semplice mantenere anche un elenco di inode associati a ogni processo 'cwd e fare riferimento a quello quando ne vede un uso ... Naturalmente, ciò significherebbe che i collegamenti simbolici dovrebbero essere creati tenendo conto di ciò, ma devi già stare attento a non rompere i collegamenti simbolici e non penso che una regola aggiuntiva li renderebbe inutili.
Parthian Shot

Mi piace questa spiegazione . Conciso e facile da leggere e / o sfogliare.
Trevor Boyd Smith,

Risposte:


143

Questa è solo una cattiva idea, in quanto non esiste alcun modo per distinguere tra un collegamento reale e un nome originale.

Consentire collegamenti rigidi alle directory spezzerebbe la struttura grafica aciclica diretta del filesystem, creando possibilmente loop di directory e sottotitoli di directory penzolanti, il che renderebbe fsckprivi di errori qualsiasi altro walker dell'albero dei file.

Innanzitutto, per capirlo, parliamo di inode. I dati nel filesystem sono mantenuti in blocchi sul disco e quei blocchi sono raccolti insieme da un inode. Puoi pensare all'inode come al file. Gli Inodi mancano di nomi di file, però. Ecco dove entrano i collegamenti.

Un collegamento è solo un puntatore a un inode. Una directory è un inode che contiene collegamenti. Ogni nome file in una directory è solo un collegamento a un inode. L'apertura di un file in Unix crea anche un collegamento, ma è un diverso tipo di collegamento (non è un collegamento denominato).

Un hard link è solo una voce di directory aggiuntiva che punta a quell'inode. Quando si ls -l, il numero dopo le autorizzazioni è il conteggio dei collegamenti denominato. La maggior parte dei file regolari avrà un link. La creazione di un nuovo collegamento reale a un file farà in modo che entrambi i nomi dei file puntino allo stesso inode. Nota:

% ls -l test
ls: test: No such file or directory
% touch test
% ls -l test
-rw-r--r--  1 danny  staff  0 Oct 13 17:58 test
% ln test test2
% ls -l test*
-rw-r--r--  2 danny  staff  0 Oct 13 17:58 test
-rw-r--r--  2 danny  staff  0 Oct 13 17:58 test2
% touch test3
% ls -l test*
-rw-r--r--  2 danny  staff  0 Oct 13 17:58 test
-rw-r--r--  2 danny  staff  0 Oct 13 17:58 test2
-rw-r--r--  1 danny  staff  0 Oct 13 17:59 test3
            ^
            ^ this is the link count

Ora puoi vedere chiaramente che non esiste un collegamento reale. Un collegamento reale è uguale a un nome normale. Nell'esempio precedente, testoppure test2, qual è il file originale e qual è il collegamento reale? Alla fine, non puoi davvero dirlo (anche per i timestamp) perché entrambi i nomi indicano lo stesso contenuto, lo stesso inode:

% ls -li test*  
14445750 -rw-r--r--  2 danny  staff  0 Oct 13 17:58 test
14445750 -rw-r--r--  2 danny  staff  0 Oct 13 17:58 test2
14445892 -rw-r--r--  1 danny  staff  0 Oct 13 17:59 test3

Il -iflag per lsmostrare i numeri di inode all'inizio della riga. Nota come teste test2ha lo stesso numero di inode, ma ne test3ha uno diverso.

Ora, se ti fosse permesso di farlo per le directory, due diverse directory in punti diversi nel filesystem potrebbero puntare alla stessa cosa. In effetti, un sottodir potrebbe indicare il nonno, creando un ciclo.

Perché questo loop è un problema? Perché quando attraversi, non c'è modo di rilevare che stai eseguendo un ciclo (senza tenere traccia dei numeri di inode mentre attraversi). Immagina di scrivere il ducomando, che deve ricorrere ai sottodirectory per scoprire l'utilizzo del disco. Come farebbe a dusapere quando ha colpito un ciclo? È soggetto a errori e molta contabilità che dudovrebbe fare, solo per svolgere questo semplice compito.

I link simbolici sono una bestia completamente diversa, in quanto sono un tipo speciale di "file" che molte API del filesystem tendono a seguire automaticamente. Nota, un collegamento simbolico può puntare a una destinazione inesistente, perché puntano per nome e non direttamente a un inode. Questo concetto non ha senso con i collegamenti reali, poiché la semplice esistenza di un "collegamento reale" significa che il file esiste.

Quindi perché dugestire facilmente i collegamenti simbolici e non i collegamenti reali? Abbiamo potuto vedere sopra che i collegamenti reali sono indistinguibili dalle normali voci della directory. I collegamenti simbolici, tuttavia, sono speciali, rilevabili e ignorabili!  dunota che il collegamento simbolico è un collegamento simbolico e lo salta completamente!

% ls -l 
total 4
drwxr-xr-x  3 danny  staff  102 Oct 13 18:14 test1/
lrwxr-xr-x  1 danny  staff    5 Oct 13 18:13 test2@ -> test1
% du -ah
242M    ./test1/bigfile
242M    ./test1
4.0K    ./test2
242M    .

7
Allowing hard links to directories would break the directed acyclic graph structure of the filesystem. Potete per favore spiegare di più sul problema con i cicli usando i collegamenti fisici? Perché va bene con i
collegamenti

33
Sembrano averlo consentito sui Mac aggiungendo il rilevamento del ciclo alla chiamata di sistema link () e rifiutando di consentire la creazione di un collegamento reale alla directory se creasse un ciclo. Sembra essere una soluzione ragionevole.
psusi,

10
@psusi mkdir -pa / b; nocheckln ca; mv ca / ​​b; - il nocheckln esiste un ln teorico che non controlla la directory args e passa semplicemente al collegamento e, poiché non viene creato alcun ciclo, siamo tutti bravi a creare 'c'. quindi spostiamo 'c' in 'a / b', e viene creato un ciclo da a / b / c -> a / - il check in link () non è abbastanza buono
Danny Dulai

3
I cicli sono molto cattivi. Windows presenta questo problema con "giunzioni" che sono directory di collegamento reale. Se si applicano accidentalmente autorizzazioni a tutto il profilo, vengono scoperte una serie di incroci che creano un ciclo infinito. Ricorrendo attraverso le directory si ricorre fino a quando le limitazioni della lunghezza del percorso lo fermano.
doug65536,

4
@WhiteWinterWolf, secondo questo link, hanno specificamente aggiunto il supporto per la macchina del tempo, ma solo root è autorizzato a farlo: superuser.com/questions/360926/…
psusi

14

Con l'eccezione di punti di montaggio, ogni directory ha un solo genitore: ...

Un modo per fare pwdè controllare il dispositivo: inode per '.' e '..'. Se sono uguali, hai raggiunto la radice del file system. Altrimenti, trova il nome della directory corrente nel genitore, inseriscilo in uno stack e inizia a confrontare "../." con '../ ..', quindi '../../.' con '../../ ..', ecc. Dopo aver toccato il root, inizia a spuntare e stampare i nomi dallo stack. Questo algoritmo si basa sul fatto che ogni directory ha uno e un solo genitore.

Se fossero consentiti collegamenti rigidi alle directory, quale dei genitori multipli dovrebbe ..indicare? Questo è uno dei motivi convincenti per cui non sono consentiti hardlink alle directory.

I collegamenti simbolici alle directory non causano questo problema. Se un programma lo desidera, potrebbe eseguire una operazione lstat()su ciascuna parte del percorso e rilevare quando viene rilevato un collegamento simbolico. L' pwdalgoritmo restituirà il vero percorso assoluto per una directory di destinazione. Il fatto che ci sia un pezzo di testo da qualche parte (il link simbolico) che punta alla directory di destinazione è praticamente irrilevante. L'esistenza di un tale collegamento simbolico non crea un ciclo nel grafico.


3
Non sono così sicuro di questo. Se pensiamo ..che sia una sorta di hardlink virtuale verso il genitore, non vi è alcun motivo tecnico per cui la destinazione del link possa avere solo un altro link ad esso. pwddovrebbe solo usare un algoritmo diverso per risolvere il percorso.
Benubird,

13

È possibile utilizzare bind mount per simulare directory di collegamento reale

sudo mount --bind /some/existing_real_contents /else/dummy_but_existing_directory
sudo umount /else/dummy_but_existing_directory

7

Mi piace aggiungere altri punti su questa domanda. I collegamenti fissi per le directory sono consentiti in Linux, ma in modo limitato.

Un modo per provarlo è quando elenchiamo il contenuto di una directory e troviamo due directory speciali "." e "..". Come sappiamo "." punta alla stessa directory e ".." punta alla directory principale.

Quindi, consente di creare un albero di directory in cui "a" è la directory padre che ha la directory "b" come figlio.

 a
 `-- b

Annotare l'inode della directory "a". E quando facciamo un ls -ladalla directory "a" possiamo vederlo "." la directory punta anche allo stesso inode.

797358 drwxr-xr-x 3 mkannan mkannan 4096 Sep 17 19:13 a

E qui possiamo trovare che la directory "a" ha tre hard link. Questo perché l'inode 797358 ha tre hardlink nel nome di "." nella directory "a" e nome come ".." nella directory "b" e una con nome "a" itslef.

$ ls -ali a/
797358 drwxr-xr-x 3 mkannan mkannan 4096 Sep 17 19:13 .

$ ls -ali a/b/
797358 drwxr-xr-x 3 mkannan mkannan 4096 Sep 17 19:13 ..

Quindi qui possiamo capire che gli hardlink sono lì per le directory solo per connettersi con le loro directory padre e figlio. Quindi una directory senza figlio avrà solo 2 hardlink, e quindi la directory "b" avrà solo due hardlink.

Uno dei motivi per cui è stato impedito il duro collegamento di directory liberamente sarebbe quello di evitare infiniti loop di riferimento che confondono i programmi che attraversano il filesystem.

Dato che il filesystem è organizzato come albero e che l'albero non può avere riferimenti ciclici, questo avrebbe dovuto essere evitato.


1
Buon esempio. Ha chiarito il mio dubbio. Quindi questi casi vengono gestiti in modo speciale per evitare cicli infiniti. giusto?
G Gill,

1
Poiché abbiamo un modo limitato di consentire collegamenti reali per le directory, ad esempio ".." e "." non raggiungeremo un ciclo infinito e quindi non avremmo bisogno di modi speciali per evitarli poiché non accadranno :)
Kannan Mohan

6

Nessuna delle seguenti è la vera ragione per cui è vietato il collegamento diretto alle directory; ogni problema è abbastanza facile da risolvere:

  • i cicli nella struttura ad albero causano un attraversamento difficile
  • genitori multipli, quindi qual è il "vero"?
  • Garbage Collection del filesystem

Il vero motivo (come suggerito da @ Thorbjørn Ravn Andersen) viene quando si elimina una directory che ha più genitori, dalla directory indicata da ..:

Cosa dovrebbe ..ora indicare?

Se la directory viene eliminata dal suo genitore ma il suo conteggio dei collegamenti è ancora maggiore di 0allora ci deve essere qualcosa, da qualche parte ancora puntando ad esso. Non puoi lasciare di non ..indicare nulla; molti programmi fanno affidamento .., quindi il sistema dovrebbe attraversare l' intero file system fino a quando non trova la prima cosa che punta alla directory eliminata, solo per l'aggiornamento ... O quello, o il file system dovrebbe mantenere un elenco di tutte le directory che puntano a una directory fortemente collegata.

In entrambi i casi, si tratterebbe di un sovraccarico prestazionale e di una complicazione aggiuntiva per i metadati e / o il codice del file system, quindi i progettisti hanno deciso di non consentirlo.


3
Anche questo è facile da risolvere: mantieni un elenco dei genitori di una directory figlio, che aggiorni quando aggiungi o rimuovi un collegamento al figlio. Quando elimini il genitore canonico (il bersaglio del figlio del bambino ..), aggiorna ..per puntare a uno degli altri genitori nell'elenco.
jathd

2
Sono d'accordo. Non scienza missilistica da risolvere. Tuttavia, un sovraccarico di prestazioni, occuperebbe un po 'più di spazio nei metadati del file system e aggiungerebbe complicazioni. E così i progettisti hanno optato per un approccio semplice e veloce: non consentire collegamenti a directory rigide.
Lqueryvg,

1
I link di Sym ai dir "violano la semantica e i comportamenti sistemati", ma sono ancora permessi. Alcuni comandi necessitano quindi di opzioni per controllare se vengono seguiti i collegamenti sym (es. -L in find e cp). Quando un programma segue '..' c'è ulteriore confusione, quindi la differenza nell'output di pwd e / bin / pwd dopo aver attraversato un collegamento sym. Non ci sono "risposte Unix"; solo decisioni di progettazione. Questo ruota attorno a ciò che diventa ".." come ho affermato nella mia risposta. Sfortunatamente, "..." non è nemmeno menzionato nella risposta per cui tutti gli altri votano così imbarazzati.
Lqueryvg,

A proposito, non sto dicendo che sono a favore di hard link a dirs. Affatto. Non voglio che il mio lavoro quotidiano sia più difficile di quanto non lo sia già.
Lqueryvg,

Non è quello che dice POSIX, ma IMO '..' non avrebbe mai dovuto essere un concetto di filesystem, piuttosto risolto sintatticamente sui percorsi, quindi a/..significherebbe sempre .. Ecco come funzionano gli URL, tra l'altro. È il browser che sta risolvendo '..' prima ancora di colpire il server. E funziona benissimo.
ybungalobill,

3

La creazione di hardlink su directory sarebbe irrevertabile. Supponiamo di avere:

/dir1
├──this.txt
├──directory
│  └──subfiles
└──etc

Lo collego a /dir2.

Quindi /dir2ora contiene anche tutti questi file e directory

E se cambio idea? Non posso semplicemente rmdir /dir2(perché non è vuoto)

E se elimino ricorsivamente in /dir2... verrà eliminato /dir1anche da !

IMHO è un motivo ampiamente sufficiente per evitarlo!

Modificare :

I commenti suggeriscono di rimuovere la directory facendo rmsu di essa. Ma rmsu una directory non vuota ha esito negativo e questo comportamento deve rimanere, indipendentemente dal fatto che la directory sia collegata o meno. Quindi non puoi semplicemente rmscollegarlo. Richiederebbe un nuovo argomento per rm, solo per dire "se l'inode della directory ha un conteggio di riferimento> 1, quindi scollegare solo la directory".

Il che, a sua volta, infrange un altro principio di minima sorpresa: significa che la rimozione di un hardlink di directory che ho appena creato non equivale alla rimozione di un normale hardlink di file ...

Riformulerò la mia frase: senza ulteriori sviluppi, la creazione di collegamenti fisici sarebbe irreversibile (poiché nessun comando corrente potrebbe gestire la rimozione senza essere incoerente con il comportamento corrente)

Se permettiamo più sviluppo per gestire il caso, il numero di insidie ​​e il rischio di perdita di dati se non si è abbastanza consapevoli di come funziona il sistema, tale sviluppo implica, IMHO è un motivo sufficiente per limitare il collegamento diretto alle directory.


Questo non dovrebbe essere un problema. Nel tuo caso, quando creiamo un hardlink in dir2, dobbiamo creare un hardlink a tutti i contenuti in dir1 e quindi se rinominiamo o eliminiamo dir2, viene eliminato solo un collegamento aggiuntivo all'inode. E ciò non dovrebbe influire su dir1 e sul suo contenuto in quanto esiste almeno un collegamento (dir1) all'inode.
Kannan Mohan,

3
Il tuo argomento non è corretto. Dovresti semplicemente scollegarlo, non fare rm -rf. E se il conteggio dei collegamenti raggiunge 0, il sistema saprebbe che può eliminare anche tutti i contenuti.
Ten.

È più o meno tutto rmciò che fa comunque sotto (scollegamento). Vedi: unix.stackexchange.com/questions/151951/… Questo in realtà non è un problema, non più di quanto lo sia con i file hardlinked. Lo scollegamento rimuove semplicemente il riferimento denominato e diminuisce il conteggio dei collegamenti. Il fatto che rmdirnon eliminerà le directory non vuote è irrilevante - non lo farebbe neanche per dir1 . I collegamenti fisici non sono copie di dati, sono lo stesso file effettivo, quindi effettivamente "eliminando" il file dir2 cancellerebbe l'elenco di directory per dir1. Dovresti sempre scollegare.
BryKKan,

Non puoi semplicemente scollegarlo come un normale file, perché rmsu una directory non scollegarlo se non è vuoto. Vedi Modifica.
Pierre-Olivier Vares, il

1

Questa è una buona spiegazione Riguardo a "Quale dei molti genitori dovrebbe ... puntare a?" una soluzione sarebbe che un processo mantenga il suo percorso wd completo, sia come inode che come stringa. gli inode sarebbero più robusti poiché i nomi possono essere cambiati. Almeno ai vecchi tempi, c'era un inode nel core per ogni file aperto che veniva incrementato ogni volta che un file veniva aperto, decrementato alla chiusura. Quando ha raggiunto lo zero e lo spazio di archiviazione a cui puntava sarebbe stato liberato. Quando il file non fosse più aperto da nessuno, sarebbe stato abbandonato (la copia in-core). Ciò manterrebbe il percorso valido se qualche altro processo spostasse una directory in un'altra directory mentre la sottodirectory si trovava nel percorso di un altro processo. Simile a come è possibile eliminare un file aperto ma viene semplicemente rimosso dalla directory,

Le directory hard linking erano consentite liberamente in Bell Labs UNIX, almeno V6 e V7, Non so di Berkeley o versioni successive. Nessuna bandiera richiesta. Potresti fare dei loop? Sì, non farlo. È molto chiaro cosa stai facendo se fai un ciclo. Al contrario, dovresti esercitarti a annodare il nodo intorno al collo mentre stai aspettando che il tuo turno paracadutista esca da un piano se hai l'altra estremità comodamente appesa a un gancio sulla paratia.

Quello che speravo di farne oggi era collegare hardhome lhome a home in modo da poter avere / home / administ disponibile indipendentemente dal fatto che / home fosse coperta da un automout su home, quell'automount con un link simbolico chiamato administ to / lhome / administ. Questo mi permette di avere un account amministrativo che funziona indipendentemente dallo stato del mio file system principale. Questo è un esperimento per Linux, ma penso che sia stato appreso in una volta per il SunOS basato su UCB che gli automount sono fatti a livello di stringa ASCII. È difficile vedere come potrebbero essere fatti diversamente come strato sopra qualsiasi FS arbitrario.

L'ho letto altrove. e .. non sono più file neanche nella directory. Sono sicuro che ci sono buone ragioni per tutto questo e che gran parte di ciò che ci piace (come essere in grado di montare NTFS) è possibile a causa di tali cose, ma parte dell'eleganza di UNIX era nell'implementazione. Sono i benefici come la generalità e la malleabilità che questa eleganza ha fornito che le hanno permesso di essere così robusto e durare per quattro decenni. Man mano che perdiamo le eleganti implementazioni alla fine diventerà come Windows (spero di sbagliarmi!). Qualcuno avrebbe quindi creato un nuovo sistema operativo basato su principi eleganti. Qualcosa a cui pensare. Forse mi sbaglio, non ho (ovviamente) familiarità con l'attuale implementazione. Lo è stupendo però quanto sia valida la comprensione trentennale per Linux ... il più delle volte!


Penso che, anche se potrei sbagliarmi, questo .e ..non sono collegamenti fisici nel file system, per i file system moderni. Tuttavia, il driver del file system li falsifica. Sono questi file system che bloccano le directory di collegamento hard. Per i vecchi file system era possibile (ma pericoloso). Per fare quello che stai provando, guarda mount --bind, vedi anche mount --make…e forse i contenitori.
ctrl-alt-delor,

0

Da quello che raccolgo, il motivo principale è che è utile poter cambiare i nomi delle directory senza incasinare i programmi in esecuzione che usano la loro directory di lavoro per fare riferimento ad altri file. Supponiamo che tu stia usando Wine per l'esecuzione ~/.newwineprefix/drive_c/Program Files/Firefox/Firefox.exee che tu volessi spostare invece l'intero prefisso ~/.wine. Se per qualche strana ragione a cui accedesse Firefox drive_c/windowsfacendo riferimento ../../windows, rinominando le ~/.newwineprefiximplementazioni di ..tali interruzioni , si tiene traccia della directory principale come stringa di testo anziché come inode.

Memorizzare l'inode di una singola directory padre deve essere più semplice che cercare di tenere traccia di ogni percorso sia come stringa di testo che come serie di inode.

Un altro motivo è che le applicazioni che si comportano in modo inappropriato potrebbero essere in grado di creare loop. Le applicazioni che si comportano dovrebbero essere in grado di verificare se l'inode della directory che viene spostata è uguale all'inode di una qualsiasi delle directory nidificate in cui viene spostata, proprio come non è possibile spostare una directory in se stessa, ma questo potrebbe non essere applicato a livello di filesystem.

Ancora un altro motivo potrebbe essere che se si potessero hardlink directory, si vorrebbe impedire il hardlink di una directory che non è possibile modificare. findha considerazioni di sicurezza perché viene utilizzato per cancellare i file creati da altri utenti da directory temporanee, il che può causare problemi se un utente cambia una directory reale per un collegamento simbolico mentre findsta invocando un altro comando. Essere in grado di collegare in modo diretto importanti directory costringerebbe un amministratore ad aggiungere ulteriori test findper evitare di influenzarli. (Ok, non puoi già farlo per i file, quindi questo motivo non è valido.)

Ancora un altro motivo è che la memorizzazione dell'inode della directory padre può fornire ridondanza aggiuntiva in caso di danneggiamento o danneggiamento del file system. Se si desidera ..elencare tutte le directory principali che si collegano a questa, quindi è possibile trovare facilmente un genitore diverso e arbitrario se quello corrente è delink, non solo si sta violando l'idea che gli hard link siano uguali, è necessario modificare il modo in cui il file system memorizza e utilizza gli inode. Fare in modo che i programmi trattino i percorsi come una serie (unica per ciascun collegamento fisico) di inode di directory eviterebbe questo, ma non si otterrebbe la ridondanza in caso di danni al file system.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.