Copie de fichiers en C

La commande cp(1) semble bien innocente. Nous allons voir qu'elle n'est pas si évidente à programmer en C.

Exercices

Dans ce qui suit, la partie I est obligatoire et à réaliser en premier. Les parties II et III proposent des extensions indépendantes les unes des autres et de difficulté similaire. Vous pouvez les réaliser dans l'ordre qu'il vous plaît (et terminer chez vous celles que vous n'avez pas eu le temps de finir en TP).

I - Copie simple d'un fichier

1) Écrivez un programme C qui copie un fichier grâce aux fonctions bas-niveau read(2) et write(2). Le programme prendra deux arguments sur sa ligne de commande: le nom d'un fichier source existant et un nom du fichier destination. On prendra en particulier soin à:

Correction) copy1.c.

2) Modifiez votre programme pour qu'il respecte les droits et le propriétaire (utilisateur et groupe) du fichier source (de manière similaire à cp -p). (Utile quand le programme est appelé par le super-utilisateur.)

Correction) copy2.c. On utilise stat(2) ainsi que chown(2) et chmod(2).

3) Que se passe-t-il si on essaye de copier un fichier sur lui-même? Modifiez votre programme pour interdire cela. (Attention aux liens symboliques et durs.)

Correction) On se sert des champs st_ino e st_dev de la structure stat pour déterminer si deux fichiers correspondent au même inode. Cette technique est utilisée dans copy2.c.

II - Fichiers creux

4) Certains systèmes de fichiers supportent les fichiers creux dans lesquels des plages de zéros ne sont pas stockées sur le disque. Modifiez votre programme pour que les trous du fichier source soient copiés comme des trous dans le fichier destination au lieu de zones pleines de zéros (voir lseek(2)).

Note. Utilisez les commandes dd(1) et stat(1) pour créer des fichiers creux et vérifier le bon fonctionnement de votre programme.

Correction) copy4.c. On utilise d'abord ftruncate(2) pour créer un fichier destination creux de la bonne taille. (Ceci n'est possible que si le champ st_size de stat indique une taille strictement positive; sinon, on a affaire à un fichier spécial.) Dans la boucle de copie, chaque bloc lu par read(2) est alors examiné. Si il n'est composé que de zéros, le write(2) est remplacé par un lseek(2).

III - Gestion des répertoires

5) Modifiez votre programme pour que, si le fichier destination contient des noms de répertoires inexistants, ceux-ci soient automatiquement créés (comme avec mkdir -p).

Correction) copy5.c.

6) Faites un programme qui copie un répertoire complet, en copiant récursivement ses sous-répertoires (voir opendir(3), readdir(3) et closedir(3)).

Correction) copy6.c.


Antoine Miné