Existe-t-il un meilleur moyen que d'essayer simplement d'ouvrir le fichier?
int exists(const char *fname)
{
FILE *file;
if ((file = fopen(fname, "r")))
{
fclose(file);
return 1;
}
return 0;
}
c
filesystems
cross-platform
Dave Marshall
la source
la source
fopen()
/fclose()
est que vous ne pourrez peut-être pas ouvrir un fichier en lecture même s'il existe. Par exemple,/dev/kmem
existe, mais la plupart des processus ne peuvent pas l'ouvrir même pour la lecture./etc/shadow
est un autre de ces fichiers. Bien sûr, les deuxstat()
etaccess()
dépendent de pouvoir accéder au répertoire contenant le fichier; tous les paris sont désactivés si vous ne pouvez pas le faire (aucune autorisation d'exécution sur le répertoire contenant le fichier).if (file = fopen(fname, "r"))
donnera un avertissement. Utilisez des parenthèses autour de l'instruction à l'intérieur de l'instruction ifif ((file = fopen(fname, "r")))
Réponses:
Recherchez la
access()
fonction, trouvée dansunistd.h
. Vous pouvez remplacer votre fonction parVous pouvez également utiliser
R_OK
,W_OK
etX_OK
à la place deF_OK
pour vérifier l'autorisation de lecture, l'autorisation d'écriture et exécuter l'autorisation (respectivement) plutôt que l'existence, et vous pouvez OU l'un ou l'autre ensemble (c.-à-d. Vérifier les autorisations de lecture et d' écriture à l'aideR_OK|W_OK
)Mise à jour : Notez que sous Windows, vous ne pouvez pas utiliser
W_OK
pour tester de manière fiable l'autorisation d'écriture, car la fonction d'accès ne prend pas en compte les DACL.access( fname, W_OK )
peut renvoyer 0 (succès) car le fichier n'a pas l'attribut en lecture seule défini, mais vous ne pouvez toujours pas avoir l'autorisation d'écrire dans le fichier.la source
access()
rupture de mon code. Je suis passé de DevC ++ à CodeBlocks et cela a cessé de fonctionner. Donc, ce n'est pas infaillible; +1 de plus à @Leffler.access()
pour vérifier l'existence d'un fichier), mais dans un programme SUID ou SGID, même cela peut être incorrect. Si le fichier testé se trouve dans un répertoire auquel le véritable UID ou le vrai GID ne peut pas accéder, il seaccess()
peut qu'il ne signale aucun fichier de ce type lorsqu'il existe. Ésotérique et improbable? Oui.Utilisez
stat
comme ceci:et appelez-le comme ceci:
la source
access()
pose également des problèmes, et il existe des options à utiliser pour créeraccess()
etstat()
travailler avec des fichiers volumineux (plus de 2 Go).stat
souffre pas de la même vulnérabilité TOCTOU queaccess
? (Ce n'est pas clair pour moi que ce serait mieux.)stat()
etaccess()
souffrent de la vulnérabilité TOCTOU (il en va de mêmelstat()
, maisfstat()
c'est sûr). Cela dépend de ce que vous allez faire en fonction de la présence ou de l'absence du fichier. L'utilisation des bonnes optionsopen()
est généralement la meilleure façon de résoudre les problèmes, mais il peut être difficile de formuler les bonnes options. Voir aussi les discussions sur EAFP (plus facile à demander pardon que permission) et LBYL (Look Before You Leap) - voir LBYL vs EAFP en Java , par exemple.Habituellement, lorsque vous souhaitez vérifier si un fichier existe, c'est parce que vous souhaitez créer ce fichier s'il ne l'est pas. La réponse de Graeme Perrow est bonne si vous ne voulez pas créer ce fichier, mais elle est vulnérable à une condition de concurrence si vous le faites: un autre processus pourrait créer le fichier entre vous en vérifiant s'il existe, et vous l'ouvrez réellement pour y écrire . (Ne riez pas ... cela pourrait avoir de mauvaises implications sur la sécurité si le fichier créé était un lien symbolique!)
Si vous souhaitez vérifier l'existence et créer le fichier s'il n'existe pas, de manière atomique afin qu'il n'y ait pas de conditions de concurrence, alors utilisez ceci:
la source
open(2)
(sous Linux; les pages de manuel de votre système d'exploitation peuvent varier), mais elles sont plutôt laides et peuvent ne pas résister à un attaquant malveillant.FILE*
, vous devez ensuite utiliser la méthode posixfdopen(fd,"flags")
pour générer unFILE*
Oui. Utilisez
stat()
. Voir la page de manuel pourstat(2)
.stat()
échouera si le fichier n'existe pas, sinon il est fort probable qu'il réussisse. S'il existe, mais que vous n'avez pas d'accès en lecture au répertoire où il se trouve, il échouera également, mais dans ce cas, n'importe quelle méthode échouera (comment pouvez-vous inspecter le contenu d'un répertoire que vous ne voyez pas selon les droits d'accès? Tout simplement, vous ne pouvez pas).Oh, comme quelqu'un l'a mentionné, vous pouvez également l'utiliser
access()
. Cependant, je préfèrestat()
, car si le fichier existe, il me fournira immédiatement beaucoup d'informations utiles (quand a-t-il été mis à jour pour la dernière fois, quelle est sa taille, propriétaire et / ou groupe propriétaire du fichier, autorisations d'accès, etc.).la source
access()
vérifie les autorisations d'accès aux fichiers d'un fichier et celles-ci sont stockées dans l'inode pour ce fichier et ne sont pas dans son entrée de répertoire (au moins pour tous les systèmes de fichiers qui ont des structures de type inode) . Ilaccess()
faut donc accéder à l'inode exactement de la même manière questat()
pour y accéder. Donc, ce que vous dites n'est vrai que si vous ne vérifiez aucune autorisation! Et en fait sur certains systèmesaccess()
est même implémenté par dessusstat()
(par exemple la glibc sur GNU Hurd le fait de cette façon), donc il n'y a aucune garantie en premier lieu.la source
(fopen_s(file, "sample.txt", "r"))
carfopen()
est considéré comme obsolète (ou désactiver les erreurs dépréciées, mais ce n'est pas recommandé).fopen()
est le standard C, ça ne va nulle part. Il est seulement "déconseillé" par Microsoft. Ne l'utilisezfopen_s()
que si vous souhaitez un code non portable spécifique à la plate-forme.De l'aide de Visual C ++, j'aurais tendance à aller avec
Il convient également de noter les valeurs de mode de :
_access(const char *path,
int mode
)
00: Existence uniquement
02: autorisation d'écriture
04: autorisation de lecture
06: autorisation de lecture et d'écriture
Comme votre
fopen
pourrait échouer dans des situations où le fichier existait mais n'a pas pu être ouvert comme demandé.Edit: Il suffit de lire le post de Mecki.
stat()
ressemble à une façon plus nette d'aller. Ho hum.la source
Vous pouvez utiliser la fonction realpath ().
la source
Je pense que la fonction access () , qui se trouve dans,
unistd.h
est un bon choix pourLinux
(vous pouvez aussi utiliser stat ).Vous pouvez l'utiliser comme ceci:
Et vous obtenez la sortie suivante:
la source