Re: Ada.Text_IO - Interruption penda nt l'écriture

Thomas De Contes via Ada-france <[email protected]> Wed, 12 Jan 2022 20:17:35 +0100
Newsgroups gmane.comp.lang.ada.france
Message-ID <[email protected]>
Le 10 janv. 2022 à 22:27, Stephane Carrez via Ada-france a écrit :

> Hi!

Merci pour cette réponse bien complète ! :-)

> 
> On 10/01/2022 00:52, Thomas De Contes via Ada-france wrote:
>> Le 6 déc. 2021 à 22:34, Jean-Pierre Rosen a écrit :
>>> Le 06/12/2021 à 16:25, Thomas De Contes a écrit :
>>>> En fait, l'usage que je voulais en faire c'est implémenter un mécanisme pour minimiser les inconvénients en cas d'interruption pendant l'écriture  :
>>>> - Trouver un répertoire pour fichiers temporaires
>>>> - Écrire le nouveau fichier dedans
>>>> - Effacer l'ancien fichier
>>>> - Déplacer le nouveau fichier à sa place
>>>> Ça permet de remplacer l'ancien fichier par le nouveau de façon quasi-atomique (pas tout à fait, puisqu'on doit faire Ada.Directories.Delete_File avant Ada.Directories.Rename, mais presque).
>>>> As-tu des recommandations à me donner dans ce domaine ?
>>> En fait, il y a une séquence critique, et il parait que certains trous de sécurité exploitent des choses comme ça: entre le moment où tu effaces le fichier et celui du move, un intrus peut créer un fichier piégé avec le nom qui va bien... C'est un peu parano, mais plutôt que d'effacer l'ancien fichier, il vaut peut-être mieux l'écraser avec le nouveau.
>> Ada.Directories.Rename refuse d'écraser un fichier.
> 
> Oui, et c'est problématique pour moi.


> 
>> Est-ce que ta suggestion c'est de :
>> - Créer un fichier temporaire, et le fabriquer comme on veut
>> - Ouvrir l'ancien fichier en écriture, et recopier le fichier temporaire dedans le plus rapidement possible
>> ?
> 
> En fait cela pose plus des problèmes d'intégrité d'écriture de fichier.
> 
> Avec ce pattern Ada, si on n'a pas assez d'espace sur le disque, il y a une écriture partielle.
> Comme on écrit (copie) sur le même nom, on a perdu l'ancien fichier.
> A mon avis, il faut éviter cela.

ah oui, j'oublie toujours le manque d'espace disque. Même si on prépare son fichier avant, pour parer aux autres exceptions, il peut toujours arriver ça.

> 
> L'autre pattern Ada qui consiste à supprimer l'ancien fichier avant le Ada.Directories.Rename
> est moins problématique mais toujours incorrect si le programme est interrompu/suspendu/tué entre
> le Delete et le Rename.

Je prévois de mettre le fichier temporaire dans le même répertoire que le fichier à remplacer.
Petit inconvénient si le programme est interrompu pendant son écriture : ça salira un peu le paysage.
Gros avantage si le programme est interrompu entre le Delete et le Rename : ça sera très facile pour l'utilisateur de le récupérer ! :-)

> 
> Le pattern recommandé sous Unix depuis plus de 40 ans est:
> 
> - écrire dans un fichier temporaire sur le même file système que le fichier à remplacer,

Ok. En prévoyant de le mettre dans le même répertoire, ça me donne cette garantie, que je n'aurais pas eue si j'avais pu obtenir le répertoire pour fichiers temporaires du système.
Donc tout va bien de ce coté là. :-)

> - une fois qu'on est sûr que ce fichier temporaire est bien écrit correctement,
>  utiliser rename(2) pour remplacer le fichier par le fichier temporaire.
> 
> Bonus: sous Unix, le rename(2) est atomique.
> Le fichier existe toujours: soit c'est l'ancien, soit c'est le nouveau.
> Les systèmes de fichiers Unix ont été conçus de longue date pour garantir
> cela même si l'OS crash pendant l'appel système rename(2).

:-)

> 
> J'avais proposé en 2018 de faire évoluer Ada.Directories.Rename pour supporter cela.
> Cela aurait pu être fait facilement en ajoutant un paramètre optionnel autorisant
> le remplacement si le fichier cible existe déjà.

Oui, avec un booléen ou un Form, ou les 2. (Il faut probablement un Form si on veut pouvoir indiquer quelle méthode on préfère dans le cas où l'OS ne permet pas un "rename" atomique.)

Pourquoi ça a été refusé ?

> 
> Pour éviter ces problèmes, j'utilise mon propre Util.Files.Rename(Old_Name, New_Name : String)
> qui fonctionne pour Unix et Windows.

(Est-ce que sous Windows aussi c'est atomique ?)

> 
> 
>> J'ai un peu de mal à voir quel genre de faille ça évite.

> Le pattern Ada (Delete, Rename) a effectivement un trou de sécurité si après le Delete
> mais avant le Rename, un autre process écrit le fichier: le Rename échouera et on se
> retrouve avec le fichier écrit par l'autre process.

En fait je crois que ça ne me concerne pas tellement,
parce que pour que ça ait un sens il faut que le processus malveillant ait à la fois la possibilité de créer un nouveau fichier dans le répertoire parent, mais pas de modifier un fichier existant.
Ça doit arriver couramment avec les serveurs et les outils système, mais rarement avec les applications "planplan" dans lesquelles les utilisateurs se contentent d'enregistrer des documents dans leur espace utilisateur,
et je suis dans le 2ème cas.

(Ça n'empêche pas d'améliorer le langage si on peut.)

> 
> Maintenant, la séquence Delete, Rename est beaucoup plus rapide que de faire une copie.

Voilà, je pensais bien avoir fait le maximum autorisé par le langage :-)


-- 
RAPID maintainer
http://savannah.nongnu.org/projects/rapid/

_______________________________________________
Ada-france mailing list
[email protected]
https://mail.ada-france.org/cgi-bin/mailman/listinfo/ada-france