¿Hay una mejor manera que simplemente intentar abrir el archivo?
int exists(const char *fname)
{
FILE *file;
if ((file = fopen(fname, "r")))
{
fclose(file);
return 1;
}
return 0;
}
c
filesystems
cross-platform
Dave Marshall
fuente
fuente
fopen()
/fclose()
es que es posible que no pueda abrir un archivo para leerlo aunque exista. Por ejemplo,/dev/kmem
existe, pero la mayoría de los procesos no pueden abrirlo ni siquiera para leer./etc/shadow
es otro de esos archivos. Por supuesto, tantostat()
yaccess()
confiar en la posibilidad de acceder al directorio que contiene el archivo; todas las apuestas están desactivadas si no puede hacerlo (sin permiso de ejecución en el directorio que contiene el archivo).if (file = fopen(fname, "r"))
Dará una advertencia. Use paréntesis alrededor de la declaración dentro de la declaración ifif ((file = fopen(fname, "r")))
Respuestas:
Busque la
access()
función, que se encuentra enunistd.h
. Puede reemplazar su función conTambién puede usar
R_OK
,W_OK
yX_OK
en lugar deF_OK
verificar el permiso de lectura, el permiso de escritura y el permiso de ejecución (respectivamente) en lugar de la existencia, y puede O cualquiera de ellos juntos (es decir, verificar el permiso de lectura y escritura usandoR_OK|W_OK
)Actualización : Tenga en cuenta que en Windows, no puede usar
W_OK
para probar de forma confiable el permiso de escritura, ya que la función de acceso no tiene en cuenta las DACL.access( fname, W_OK )
puede devolver 0 (correcto) porque el archivo no tiene establecido el atributo de solo lectura, pero es posible que aún no tenga permiso para escribir en el archivo.fuente
access()
rompió mi código. Me mudé de DevC ++ a CodeBlocks y dejó de funcionar. Entonces, no es infalible; +1 más a @Leffler.access()
para verificar la existencia de un archivo), pero en un programa SUID o SGID, incluso eso podría ser incorrecto. Si el archivo probado está en un directorio al que el UID real o el GID real no pueden acceder, esaccess()
posible que no se informe de dicho archivo cuando exista. ¿Esotérico e improbable? Si.Usar
stat
así:y llámalo así:
fuente
access()
también tenga problemas, y hay opciones para usar para crearaccess()
ystat()
trabajar con archivos grandes (más de 2 GB).stat
No sufre la misma vulnerabilidad TOCTOU queaccess
? (No está claro para mí que sería mejor.)stat()
yaccess()
sufren la vulnerabilidad TOCTOU (también lo hacelstat()
, perofstat()
es seguro). Depende de lo que va a hacer en función de la presencia o ausencia del archivo. Usar las opciones correctasopen()
suele ser la mejor manera de lidiar con los problemas, pero puede ser complicado formular las opciones correctas. Vea también las discusiones sobre EAFP (más fácil pedir perdón que permiso) y LBYL (mirar antes de saltar ); vea LBYL vs EAFP en Java , por ejemplo.Por lo general, cuando desea verificar si existe un archivo, es porque desea crear ese archivo si no existe. La respuesta de Graeme Perrow es buena si no desea crear ese archivo, pero es vulnerable a una condición de carrera si lo hace: otro proceso podría crear el archivo entre usted comprobando si existe, y en realidad lo abre para escribir en él . (No se ría ... ¡esto podría tener malas implicaciones de seguridad si el archivo creado fuera un enlace simbólico!)
Si desea verificar la existencia y crear el archivo si no existe, atómicamente para que no haya condiciones de carrera, use esto:
fuente
open(2)
(en Linux; las páginas de manual de su sistema operativo pueden variar), pero es bastante fea y puede no ser resistente a un atacante malintencionado.FILE*
, debe usar el método posixfdopen(fd,"flags")
para generar unFILE*
Si. Uso
stat()
. Vea la página del manual parastat(2)
.stat()
fallará si el archivo no existe, de lo contrario lo más probable es que tenga éxito. Si existe, pero no tiene acceso de lectura al directorio donde existe, también fallará, pero en ese caso fallará cualquier método (¿cómo puede inspeccionar el contenido de un directorio que puede no ver de acuerdo con los derechos de acceso? Simplemente no puedes).Oh, como alguien más mencionó, también puedes usar
access()
. Sin embargo, prefierostat()
, ya que si el archivo existe, inmediatamente me dará mucha información útil (cuándo se actualizó por última vez, qué tan grande es, el propietario y / o grupo que posee el archivo, los permisos de acceso, etc.).fuente
access()
verifica los permisos de acceso a archivos de un archivo y estos se almacenan en el inodo para ese archivo y no están en su entrada de directorio (al menos para todos los sistemas de archivos que tienen estructuras tipo inodo) . Entoncesaccess()
tiene que acceder al inodo exactamente de la misma manera questat()
tiene que acceder a él. ¡Entonces lo que dices solo es cierto si no verificas los permisos! Y en realidad, en algunos sistemasaccess()
incluso se implementa por encimastat()
(por ejemplo, glibc en GNU Hurd lo hace de esa manera), por lo que no hay garantía en primer lugar.fuente
(fopen_s(file, "sample.txt", "r"))
ya quefopen()
se considera obsoleto (o deshabilite los errores obsoletos, pero eso no se recomienda).fopen()
es estándar C, no va a ninguna parte. Solo está "en desuso" por Microsoft. No lo use afopen_s()
menos que desee un código no portátil específico de la plataforma.De la ayuda de Visual C ++, tendería a ir con
También vale la pena señalar los valores de modo de :
_access(const char *path,
int mode
)
00: solo existencia
02: Escribir permiso
04: permiso de lectura
06: permiso de lectura y escritura
Como
fopen
podría fallar en situaciones donde el archivo existía pero no se podía abrir como se solicitó.Editar: Acabo de leer la publicación de Mecki.
stat()
parece un camino más ordenado. Ho hum.fuente
Puede usar la función realpath ().
fuente
Creo que la función access () , que se encuentra en
unistd.h
es una buena opción paraLinux
(también puede usar stat ).Puedes usarlo así:
Y obtienes el siguiente resultado:
fuente