Mantenere (o ripristinare) le autorizzazioni per i file quando si sostituisce il file


11

Ho un comando che accetta un file come argomento, modifica il file, quindi lo scrive nel nome file specificato nel secondo argomento. Chiamerò quel programma modifyfile.

Volevo che funzionasse "sul posto", quindi ho scritto uno script di shell (bash) che lo modifica in un file temporaneo e poi lo sposta indietro:

TMP=`mktemp`
modifyfile "$original" "$TMP"
mv -v "$TMP" "$original"

Questo ha lo sfortunato effetto collaterale di distruggere le autorizzazioni su questo file. Il file viene ricreato con le autorizzazioni predefinite.

C'è un modo per dire al mvcomando di sovrascrivere la destinazione senza alterarne le autorizzazioni? O in alternativa c'è un modo per salvare l'utente, il gruppo e le autorizzazioni dall'originale e ripristinarli?

Risposte:


10

Invece di usare mv, basta reindirizzare cat. Per esempio:

TMP=$(mktemp)
modifyfile "$original" "$TMP"
cat "$TMP" > "$original"

Questo si sovrascrive $originalcon il contenuto di $TMP, senza toccare nulla a livello di file.


Non potrebbe essere problematico se un programma ha un handle di file aperto nel file?
Martin von Wittich,

2
Devo anche io rm "$TMP", ma sembra fare proprio quello che voglio.
Stephen Ostermiller,

@MartinvonWittich sarebbe probabilmente un problema se si utilizzasse mvinvece. Non vedo un modo per risolvere quel problema.
Strugee,

2
@MartinvonWittich Sì. Create-new-then-move ti dà una modifica atomica e non influisce sui programmi che hanno il file aperto, ma poiché crea un nuovo file la proprietà e le autorizzazioni del file vengono perse. Troncare-esistente-quindi-scrivere conserva le autorizzazioni e la proprietà ma perde i dati in caso di arresto anomalo e fa scorrere il tappeto sotto i piedi dei programmi che hanno il file aperto. Non puoi combinare le parti buone di entrambi.
Gilles 'SO- smetti di essere malvagio' il

1
@MartinvonWittich chownfunziona solo come root. chmode chgrppuò o meno funzionare a seconda delle autorizzazioni dell'utente. Né copia altri attributi come ACL o attributi estesi specifici del filesystem.
Gilles 'SO- smetti di essere malvagio' il

10

Esistono due strategie per sostituire un file con una nuova versione:

  1. Crea un file temporaneo con la nuova versione, quindi spostalo in posizione.

    • Vantaggio: se un programma apre quel file, leggerà il vecchio contenuto o il nuovo contenuto, a seconda che abbia aperto il file prima o dopo lo spostamento. Non c'è confusione.
    • Vantaggio: in caso di crash, il vecchio contenuto viene preservato.
    • Unico inconveniente: poiché viene creato un nuovo file, gli attributi del file (proprietà, autorizzazione, ecc.) Non vengono conservati.
  2. Sovrascrivi il vecchio file in atto.

    • Vantaggio: gli attributi del file vengono conservati.
    • Unico inconveniente: in caso di crash, il file può essere lasciato mezzo scritto.
    • Unico inconveniente: se un programma ha il file aperto durante l'aggiornamento, questo programma potrebbe leggere dati incoerenti.

Se possibile, utilizzare il metodo 1, ma prima replicare gli attributi del file originale con cp -p --attributes-only. Ciò richiede coreutils GNU (ovvero Linux non incorporato o ambienti sufficientemente simili a Linux). Se cpnon lo hai --attributes-only, ometti questa opzione: funzionerà ma replicherà anche i dati.

tmp=$(mktemp)
cp -p --attributes-only "$original" "$tmp"
modifyfile "$original" "$tmp"
mv -f "$tmp" "$original"

Se non è possibile replicare gli attributi del file esistente, ad esempio perché si dispone di autorizzazioni di scrittura ma non lo si possiede e si desidera preservare il proprietario, è possibile solo il metodo 2. Per ridurre al minimo il rischio di perdita di dati:

  • Rendi la finestra durante la quale il file sarà incompleto il più piccolo possibile. Preparare prima i dati in un file temporaneo, quindi copiarli in posizione.
  • Prima fai un backup del vecchio file.

tmp=$(mktemp)
backup="${original}~"
modifyfile "$original" "$tmp"
cp -p "$original" "$backup"
cp -f "$tmp" "$original"

Bella risposta! Oggi suggerirei di usare l'argomento --attributes-only con il comando cp nel Metodo 1 . In questo modo, cp -p --attributes-only "$original" "$tmp"non utilizzerà le risorse per copiare il contenuto del file. Non sono riuscito a trovare da quale versione è stato aggiunto questo argomento.
Marcelo Barros,

@MarceloBarros È stato aggiunto in GNU coreutils 8.6 rilasciato il 15-10-2010, quindi in questi giorni se hai GNU coreutils dovresti averlo. Non c'è ancora nulla di simile con altre cpimplementazioni.
Gilles 'SO- smetti di essere malvagio' il

5

Dopo la nostra discussione sulla prima risposta, propongo una risposta diversa:

TMP="$(mktemp "$original".XXXXXXXXXX)"
modifyfile "$original" "$TMP"
chmod --reference="$original" "$TMP"
chown --reference="$original" "$TMP"
mv -f "$TMP" "$original"

Osservazioni:

  • Uso $originalil mktempmodello per assicurarmi che il file temporaneo non sia inserito /tmpma nella stessa cartella di $original. Credo che se /tmpfosse montato su un diverso filesystem l'operazione non sarebbe più atomica.
  • Il risultato di mktempviene ora citato nel caso contenga spazi bianchi.
  • Uso $()invece di `` perché lo considero più pulito.
  • ch{mod,own} --referencevengono utilizzati per trasferire le autorizzazioni di $originala $TMP. Se qualcuno ha ulteriori idee su quali metadati possono e devono essere trasferiti, modifica il mio post e aggiungilo.
  • Vabbè, questo richiede i permessi di root come ha sottolineato Gilles. Bene, non ho intenzione di scartare questo ora che l'ho scritto: P
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.