Vérifier la validité d’un pointeur de fichier en C tant que le fichier est ouvert

En général, une fois que le handle du fichier est ouvert, le fichier est ouvert et personne ne peut modifier la structure du répertoire – le fichier peut être déplacé, renommé ou placé à sa place – il rest ouvert par construction, comme sous Linux / Unix, il n’y a pas de suppression réelle pour les fichiers, mais uniquement la unlink , ce qui ne supprime pas nécessairement le fichier – elle supprime simplement le lien du répertoire. Résultat: le descripteur de fichier restra valide, quoi qu’il arrive au fichier.

Toutefois, si le périphérique sous-jacent disparaît (par exemple, le fichier se trouve sur une clé USB retirée du système), le fichier ne sera plus accessible.

J’ai un programme qui ouvre un énorme fichier binary (> 4 Go) d’une autre application au départ. Ensuite, il surveille le fichier pour y rechercher les modifications, en interrogeant

 long int pos = fseek(filepointer, 0L, SEEK_END); 

assez souvent (toutes les quelques millisecondes) et revient aux positions précédentes, si le résultat est différent de pos_before . Dans ce cas, fgets est utilisé pour lire les nouvelles données du fichier.

Par conséquent, seule la queue du fichier est analysée pour rechercher des modifications, ce qui rend l’ensemble du processus assez léger. Cependant, il est possible que le pointeur de fichier toujours ouvert devienne invalide si le système de fichiers est modifié (voir ci-dessus).

Le code n’a pas besoin d’être portable pour les systèmes non Linux / Unix.

Question:

  • Comment puis-je détecter si le pointeur de fichier est toujours valide après avoir ouvert le fichier avec succès (cet événement a peut-être des semaines)? J’ai vu que l’on pouvait utiliser fcntl(fileno(filepointer), F_GETFD) pour tester.

Question alternative:

  • Serait-il possible de détecter des changements dans la taille du fichier d’une manière alternative? Je pourrais penser à utiliser périodiquement
    • fseek(filepointer, 0L, SEEK_END); (peut être très lent et causer beaucoup d’E / S), ou
    • _filelength(fileno(filepointer)); (pas clair si cela causera beaucoup d’E / S)
    • stat(filename, &st); st.st_size; (pas clair si cela provoquera des E / S)

Eh bien, généralement, un fichier ouvert empêchera de démonter le système de fichiers, il ne devrait donc pas simplement disparaître sous vous. Bien qu’avec les disques USB etc., il est bien sûr possible que l’utilisateur tire l’appareil sans demander au système.

Mais ce serait bien de ne pas empêcher le déassembly propre. Cela nécessite deux choses:

  1. Ne conservez pas le fichier ouvert
  2. Ne conservez pas le répertoire contenant comme répertoire de travail des processus.

Exécuter périodiquement stat(2) sur le chemin serait le moyen de le faire. Vous pouvez détecter les modifications apscopes au fichier à partir des modifications apscopes à ctime , ctime , à la taille du fichier. Les erreurs et les modifications du numéro d’inode ou du périphérique contenant ( st_dev ) peuvent indiquer que le fichier n’est plus accessible ou qu’il ne s’agit plus du même fichier. Réagir en fonction des exigences de l’application.

(En supposant que vous êtes intéressé par le fichier actuellement désigné par ce nom , et non par le même inode que vous avez ouvert.)

En ce qui concerne les E / S, il est probable que quelque chose garde périodiquement en mémoire l’inode mis en cache, de sorte que le problème serait davantage lié à l’utilisation de la mémoire que les E / S. (Jusqu’à ce que vous le fassiez suffisamment pour que les fichiers ne puissent plus les mettre en cache, ce qui entraîne une destruction de la mémoire et des E / S …). le fichier, je ne vois pas pourquoi cela provoquerait des E / S significatives.

Un autre choix serait d’utiliser inotify(7) sur le fichier ou tout le répertoire pour détecter les modifications sans interrogation. Il peut également détecter des événements de déassembly.

Comment puis-je détecter si le pointeur de fichier est toujours valide après avoir ouvert le fichier avec succès

Si le FILE* n’était pas explicitement fclose() d par le processus qui l’a ouvert (ou l’a hérité) et si le processus en question n’a pas invoqué le Comportement non défini, le FILE* est valide par définition.

Si une couche sous-jacente ne peut pas répondre aux requêtes émises par le processus FILE* fp (généralement fwrite() indirectement via des appels dans LIBC comme fread() , fwrite() ou fseek() ou directement en read(fileno(fp)) ) les fonctions défaillantes devraient renvoyer une erreur et définir errno conséquence, ce serait typiquement EIO .

Il suffit de mettre en œuvre une vérification et un traitement complets des erreurs et vous ne rencontrerez aucun problème.