¿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;
}
fuente
¿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;
}
Busque la access()
función, que se encuentra en unistd.h
. Puede reemplazar su función con
if( access( fname, F_OK ) != -1 ) {
// file exists
} else {
// file doesn't exist
}
También puede usar R_OK
, W_OK
y X_OK
en lugar de F_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 usando R_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.
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, es access()
posible que no se informe de dicho archivo cuando exista. ¿Esotérico e improbable? Si.
Usar stat
así:
#include <sys/stat.h> // stat
#include <stdbool.h> // bool type
bool file_exists (char *filename) {
struct stat buffer;
return (stat (filename, &buffer) == 0);
}
y llámalo así:
#include <stdio.h> // printf
int main(int ac, char **av) {
if (ac != 2)
return 1;
if (file_exists(av[1]))
printf("%s exists\n", av[1]);
else
printf("%s does not exist\n", av[1]);
return 0;
}
access()
también tenga problemas, y hay opciones para usar para crear access()
y stat()
trabajar con archivos grandes (más de 2 GB).
stat
No sufre la misma vulnerabilidad TOCTOU que access
? (No está claro para mí que sería mejor.)
stat()
y access()
sufren la vulnerabilidad TOCTOU (también lo hace lstat()
, pero fstat()
es seguro). Depende de lo que va a hacer en función de la presencia o ausencia del archivo. Usar las opciones correctas open()
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:
#include <fcntl.h>
#include <errno.h>
fd = open(pathname, O_CREAT | O_WRONLY | O_EXCL, S_IRUSR | S_IWUSR);
if (fd < 0) {
/* failure */
if (errno == EEXIST) {
/* the file already existed */
...
}
} else {
/* now you can use the file */
}
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 posix fdopen(fd,"flags")
para generar unFILE*
Si. Uso stat()
. Vea la página del manual para stat(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, prefiero stat()
, 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.).
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) . Entonces access()
tiene que acceder al inodo exactamente de la misma manera que stat()
tiene que acceder a él. ¡Entonces lo que dices solo es cierto si no verificas los permisos! Y en realidad, en algunos sistemas access()
incluso se implementa por encima stat()
(por ejemplo, glibc en GNU Hurd lo hace de esa manera), por lo que no hay garantía en primer lugar.
FILE *file;
if((file = fopen("sample.txt","r"))!=NULL)
{
// file exists
fclose(file);
}
else
{
//File not found, no memory leak since 'file' == NULL
//fclose(file) would cause an error
}
(fopen_s(file, "sample.txt", "r"))
ya que fopen()
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 a fopen_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
/* ACCESS.C: This example uses _access to check the
* file named "ACCESS.C" to see if it exists and if
* writing is allowed.
*/
#include <io.h>
#include <stdio.h>
#include <stdlib.h>
void main( void )
{
/* Check for existence */
if( (_access( "ACCESS.C", 0 )) != -1 )
{
printf( "File ACCESS.C exists\n" );
/* Check for write permission */
if( (_access( "ACCESS.C", 2 )) != -1 )
printf( "File ACCESS.C has write permission\n" );
}
}
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.
Puede usar la función realpath ().
resolved_file = realpath(file_path, NULL);
if (!resolved_keyfile) {
/*File dosn't exists*/
perror(keyfile);
return -1;
}
Creo que la función access () , que se encuentra en unistd.h
es una buena opción para Linux
(también puede usar stat ).
Puedes usarlo así:
#include <stdio.h>
#include <stdlib.h>
#include<unistd.h>
void fileCheck(const char *fileName);
int main (void) {
char *fileName = "/etc/sudoers";
fileCheck(fileName);
return 0;
}
void fileCheck(const char *fileName){
if(!access(fileName, F_OK )){
printf("The File %s\t was Found\n",fileName);
}else{
printf("The File %s\t not Found\n",fileName);
}
if(!access(fileName, R_OK )){
printf("The File %s\t can be read\n",fileName);
}else{
printf("The File %s\t cannot be read\n",fileName);
}
if(!access( fileName, W_OK )){
printf("The File %s\t it can be Edited\n",fileName);
}else{
printf("The File %s\t it cannot be Edited\n",fileName);
}
if(!access( fileName, X_OK )){
printf("The File %s\t is an Executable\n",fileName);
}else{
printf("The File %s\t is not an Executable\n",fileName);
}
}
Y obtienes el siguiente resultado:
The File /etc/sudoers was Found
The File /etc/sudoers cannot be read
The File /etc/sudoers it cannot be Edited
The File /etc/sudoers is not an Executable
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")))