Existe uma maneira melhor do que simplesmente tentar abrir o arquivo?
int exists(const char *fname)
{
FILE *file;
if ((file = fopen(fname, "r")))
{
fclose(file);
return 1;
}
return 0;
}
c
filesystems
cross-platform
Dave Marshall
fonte
fonte
fopen()
/fclose()
é que você talvez não consiga abrir um arquivo para leitura, mesmo que ele exista. Por exemplo,/dev/kmem
existe, mas a maioria dos processos não pode abri-lo nem para leitura./etc/shadow
é outro desses arquivos. Obviamente, ambosstat()
eaccess()
dependem de poder acessar o diretório que contém o arquivo; todas as apostas estão desativadas se você não puder fazer isso (sem permissão de execução no diretório que contém o arquivo).if (file = fopen(fname, "r"))
dará um aviso. Use parênteses ao redor da instrução dentro da instrução ifif ((file = fopen(fname, "r")))
Respostas:
Procure a
access()
função, encontrada emunistd.h
. Você pode substituir sua função porVocê também pode usar
R_OK
,W_OK
eX_OK
no lugar deF_OK
verificar a permissão de leitura, a permissão de gravação e executar a permissão (respectivamente) em vez da existência, e você pode OU qualquer um deles juntos (por exemplo, verificar a permissão de leitura e gravação usandoR_OK|W_OK
)Atualização : observe que, no Windows, você não pode
W_OK
testar com confiabilidade a permissão de gravação, pois a função de acesso não leva em consideração as DACLs.access( fname, W_OK )
pode retornar 0 (êxito) porque o arquivo não possui o atributo somente leitura definido, mas você ainda pode não ter permissão para gravar no arquivo.fonte
access()
quebra no meu código. Eu mudei do DevC ++ para o CodeBlocks e ele parou de funcionar. Então, não é infalível; +1 a mais para @Leffler.access()
para verificar a existência de um arquivo), mas em um programa SUID ou SGID, mesmo isso pode estar incorreto. Se o arquivo testado estiver em um diretório que o UID real ou o GID real não puder acessar,access()
poderá reportar esse arquivo quando ele existir. Esotérico e improvável? Sim.Use
stat
assim:e chame assim:
fonte
access()
também há problemas e há opções para criaraccess()
estat()
trabalhar com arquivos grandes (maiores que 2 GB).stat
sofre a mesma vulnerabilidade de TOCTOU queaccess
? (Não está claro para mim que seria melhor.)stat()
eaccess()
sofrem com a vulnerabilidade TOCTOU (o mesmo acontecelstat()
, masfstat()
é seguro). Depende do que você fará com base na presença ou ausência do arquivo. Usar as opções corretas paraopen()
geralmente é a melhor maneira de lidar com os problemas, mas pode ser complicado formular as opções corretas. Consulte também discussões sobre EAFP (mais fácil pedir perdão do que permissão) e LBYL (veja antes de pular) - consulte LBYL vs EAFP em Java , por exemplo.Normalmente, quando você deseja verificar se um arquivo existe, é porque você deseja criar esse arquivo, se não existir. A resposta de Graeme Perrow é boa se você não deseja criar esse arquivo, mas é vulnerável a uma condição de corrida, se o fizer: outro processo pode criar o arquivo entre você, verificando se ele existe e abrindo-o para gravá-lo . (Não ria ... isso pode ter implicações ruins na segurança se o arquivo criado for um link simbólico!)
Se você deseja verificar a existência e criar o arquivo, se não existir, atomicamente , para que não haja condições de corrida, use o seguinte:
fonte
open(2)
(no Linux; as páginas de manual do seu sistema operacional podem variar), mas é bastante feia e pode não ser resistente a um invasor mal-intencionado.FILE*
, é necessário usar o método posixfdopen(fd,"flags")
para gerar umFILE*
Sim. Use
stat()
. Veja a página de manual parastat(2)
.stat()
falhará se o arquivo não existir, caso contrário, provavelmente será bem-sucedido. Se existir, mas você não tiver acesso de leitura ao diretório em que ele existe, também falhará, mas nesse caso qualquer método falhará (como você pode inspecionar o conteúdo de um diretório que talvez não seja exibido de acordo com os direitos de acesso? Simplesmente, você não pode).Ah, como alguém mencionou, você também pode usar
access()
. No entanto, prefiro questat()
, como se o arquivo exista, ele imediatamente receba muitas informações úteis (quando foi atualizada pela última vez, qual o tamanho, o proprietário e / ou o grupo que possui o arquivo, as permissões de acesso etc.).fonte
access()
verifica as permissões de acesso a um arquivo e elas são armazenadas no inode para esse arquivo e não estão em sua entrada de diretório (pelo menos para todos os sistemas de arquivos que possuem estruturas semelhantes a inode) . Entãoaccess()
tem que acessar o inode exatamente da mesma maneira questat()
tem para acessá-lo. Portanto, o que você diz é válido apenas se você não verificar nenhuma permissão! E, na verdade, em alguns sistemasaccess()
é implementado ainda por cimastat()
(por exemplo, a glibc no GNU Hurd faz dessa maneira), portanto, não há garantia em primeiro lugar.fonte
(fopen_s(file, "sample.txt", "r"))
uma vez quefopen()
é considerado obsoleto (ou desative erros obsoletos, mas isso não é recomendado).fopen()
é padrão C, não vai a lugar nenhum. É apenas "reprovado" pela Microsoft. Não use afopen_s()
menos que queira um código não portátil e específico da plataforma.Com a ajuda do Visual C ++, eu costumava usar
Também vale a pena notar os valores do modo de :
_access(const char *path,
int mode
)
00: Apenas existência
02: permissão de gravação
04: permissão de leitura
06: permissão de leitura e gravação
Como você
fopen
pode falhar em situações em que o arquivo existe, mas não pode ser aberto conforme solicitado.Edit: Basta ler a publicação de Mecki.
stat()
parece um caminho mais arrumado. Ho hum.fonte
Você pode usar a função realpath ().
fonte
Eu acho que a função access () , que é encontrada em,
unistd.h
é uma boa opção paraLinux
(você também pode usar o stat ).Você pode usá-lo assim:
E você obtém a seguinte saída:
fonte