Problema passando parâmetro para OPENDIR() [RESOLVIDO]

1. Problema passando parâmetro para OPENDIR() [RESOLVIDO]

Michel Dionisio Silva
micheldionisio

(usa Ubuntu)

Enviado em 31/01/2022 - 14:32h

Acredito que tenho um problema básico pessoal, masnão estou enxergando a resposta. Estou usando a função opendir() e passando como parâmetro um elemento de uma structs. Porém o retorno da opendir() sempre dá: "No such file or directory", erro 2. Só que eu testo a váriável antes de submeter para o opendir() e ela parece com o conteúdo corrento. Se eu coloco um texto fixo no opendir tudo funciona. Mas eu preciso trabalhar com uma variável porque o valor desse diretório está vindo de um arquivo de configuração que o aplicativo lê ao inicializar então tem que funcionar com variável. Abaixo um print da última implementação com ponteiro de char o qual é a definição do parâmetro do opendir(), mas mesmo assim não funcionou. Já testei com vetor de char fixo também, funciona em todas as partes do sistema menos na chamada do opendir(). Já testei na função scandir() também e o comportamento é identico.
int monitoraDiretorio(controle *ctr)
{
DIR *dir;
char *s;
int TstFile;
bool bin = true;

while (bin) {

// alocação de memoria dinamica para o ponteiro de caracteres
s = malloc(50);
// Montando caminho a ser trabalhado
strcpy(s,ctr->caminhoOrigem);

printf("\n O nome do diretorio a ser aberto.: %s. \n", s);

dir = opendir(s);
if (dir == NULL) {
// perror("\n Nao pode abrir o diretorio. \n\n");
printf("\n Erro na abertura do diretorio.: %d \n", errno);
printf("\n O nome do erro impresso eh.: %s. \n", strerror (errno));
exit(1);
}else{
printf("Abriu o diretorio com vetor de char s. \n");
struct dirent *lsdir;
while ( ( lsdir = readdir(dir) ) != NULL )
{
if (strcmp(lsdir->d_name,".") == 0)
continue;
if (strcmp(lsdir->d_name,"..") == 0)
continue;
// Adicionando nome do arquivo.
strcat(s,lsdir->d_name);
printf("\n Diretorio com nome de arquivo: %s. \n", s);
// Testa se o arquivo existe
TstFile = fileExists(s);
if (TstFile == 2){
// printf("Entrou no IF == 2. Valor: %d - Diretório %s nao será processado. \n", TstFile, f);
}else if (TstFile == 1){
printf ("\n Processando arquivo %s. \n\n", s);
}else
printf("\n A entrada %s não é um diretório nem um arquivo. \n", s);
}
}
closedir(dir);
sleep(10); // Dormindo por 10 segundos
}
return 0;
}


Resultado da execução:

O nome do diretorio de Origem a ser trabalhado.: /teste/cripto/origem/
.
O nome do diretorio a ser aberto.: /teste/cripto/origem/
.
Erro na abertura do diretorio.: 2
O nome do erro impresso eh.: No such file or directory.




  


2. MELHOR RESPOSTA

Paulo
paulo1205

(usa Ubuntu)

Enviado em 03/02/2022 - 23:01h

A saída do programa indica o problema. Notou que os printf()s estão imprimindo o ponto final das mensagens na linha imediatamente abaixo do nome do arquivo, mesmo sem você ter colocado uma quebra de linha entre a conversão %s e o ponto?

Isso implica que a quebra de linha está fazendo parte do nome do arquivo recebido no campo caminhoOrigem apontado pelo parâmetro ctr.

Você não mostrou como esse campo está sendo preenchido, mas você mencionou que ele vem de um arquivo de configuração. É muito provável que a função que faz a leitura desse nome esteja incluindo a quebra de linha ao preencher o conteúdo do campo do caminho de origem dos arquivos.

A função fgets(), ao ler uma linha de dados, inclui o caráter de quebra de linha como parte da linha lida, desde que tal linha não exceda o tamanho máximo do array que vai armazenar tal linha. Isso pode parecer meio inconveniente, mas tal comportamento é justamente para ajudar o seu programa a reconhecer se houve truncamento de dados lidos por falta de espaço no array que os armazena.

Sendo esse o caso, o que você pode fazer é, na função que lê o arquivo de configuração, verificar se o nome do arquivo contém uma marca de fim de linha antes do fim da string, e sobrescrever essa quebra de linha com um byte nulo, indicando o novo final da string.

Veja o exemplo abaixo do uso devido de fgets().
char buffer[PATH_MAX+1];
if(!fgets(buffer, sizeof buffer, arquivo_conf){
// Erro de leitura. Vamos examinar a causa.
if(feof(arquivo_conf)){
// Causa do erro foi ter chegado ao fim do arquivo.
/* Dá o tratamento adequado para o fim de arquivo não esperado. */
}
else if(ferror(arquivo_conf)){
// Algum erro de leitura mais sério.
/* Dá o tratamento adequado para erro de leitura. */
}
}
else {
// A leitura foi bem sucedida, tendo lido pelo menos um byte.
size_t indice_ultimo=strlen(buffer)-1;
if(buffer[indice_ultimo]=='\n'){
buffer[indice_ultimo]='\0'; // Remove a marca de quebra de linha.
if(indice_ultimo==0){
// A linha lida está vazia. No nosso caso, essa é uma situação inválida, pois esperamos um nome de arquivo, que não pode ser vazio.
/* Dá o tratamento para linha vazia. */
}
else
--indice_ultimo;
}
else {
// Linha não terminou com marca de fim de linha. Possivelmente houve truncamento.
if(indice_ultimo==sizeof buffer-1){
// Tamanho do buffer não foi suficiente para ler a linha inteira.
/* Dá o tratamento para linha maior do que o tamanho esperado. */
}
else {
// Provavelmente chegou ao final do arquivo sem encontrar a marca de fim de linha (geralmente isso não é bem aceito no mundo UNIX).
/* Dá o tratamento para linha que não contém a marca de fim de linha. */
}
}
}


Por fim, um lembrete: se o tal arquivo de configuração tiver sido gerado num editor de texto do Windows e o seu programa estiver rodando no Linux, pode ser que, além da marca do fim de linha ('\n'), haja também o caráter '\r' (carriage return, ou retorno de carro de impressão). Isso porque o mundo Windows/DOS utiliza um par de caracteres ("\r\n") para indicar quebras de linha, mas o mundo UNIX usa somente um caráter ('\n'). Assim sendo, talvez você precise examinar se existe também um '\r' no nome do arquivo, e extirpar também esse caráter, se necessário.


... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)

3. Re: Problema passando parâmetro para OPENDIR() [RESOLVIDO]

Heitor Costa
Heitor.rj

(usa Slackware)

Enviado em 01/02/2022 - 19:28h

micheldionisio escreveu: Acredito que tenho um problema básico pessoal, masnão estou enxergando a resposta. Estou usando a função opendir() e passando como parâmetro um elemento de uma structs. Porém o retorno da opendir() sempre dá: "No such file or directory", erro 2. Só que eu testo a váriável antes de submeter para o opendir() e ela parece com o conteúdo corrento. Se eu coloco um texto fixo no opendir tudo funciona. Mas eu preciso trabalhar com uma variável porque o valor desse diretório está vindo de um arquivo de configuração que o aplicativo lê ao inicializar então tem que funcionar com variável. Abaixo um print da última implementação com ponteiro de char o qual é a definição do parâmetro do opendir(), mas mesmo assim não funcionou. Já testei com vetor de char fixo também, funciona em todas as partes do sistema menos na chamada do opendir(). Já testei na função scandir() também e o comportamento é identico

Eu achei o seu código confuso, mas não vou discutir ele! Abaixo 2 formas de usar o opendir()
A forma que você fez no seu código usando um ponteiro, e a outra forma usando um vetor.
Basta compilar que funciona! Logo pode ainda usar esse exemplo pra saber se o seu PATH é de verdade válido ou não!
E creio que o seu problema reside nesta linha possivelmente: strcpy(s,ctr->caminhoOrigem);
Repare que fiz da mesma forma, ou seja o Path foi passado pra um ponteiro! LOGO se ctr->caminhoOrigem tiver um valor válido vc pode usar ele, pra isso use um printf pra imprimir na tela se ctr->caminhoOrigem está mesmo informando um caminho válido e existente no PC.
#include <stdio.h>  // puts
#include <dirent.h> // opendir
#include <errno.h> // errno

int main(void) {
// COMO VOCÊ PARECE QUERER FAZER
char *s;
s = "/mnt/dados"; // É indiferente colocar / ou não no final. Ele vai identificar se é arquivo ou pasta do mesmo jeito!
DIR *dir = opendir(s);

// OPÇÃO II, GOSTO MAIS DESSA SOLUÇÃO, Melhor que trabalhar com ponteiros! A não ser que vc precise do ponteiro por algum outro motivo
//char s[50] = "/mnt/dados";
// Aqui vc poderia usar strcpy(s,ctr->caminhoOrigem); sem maiores problemas se declarar acima char s[50];
//DIR *dir = opendir(s);

if(dir) {
puts("Exist");
closedir(dir);
} else
if(ENOENT == errno)
puts("No Exist");
else
puts("Fail"); // Se achar um arquivo com o nome do diretório! | opendir() falha
}

OBS Notei em perguntas anteriores que você fez, que você não marcou o tópico como resolvido e nem mesmo escolheu a melhor resposta!
Considero isso uma má prática! E me fez analisar se eu iria ou não responder esse tópico!
Logo espero que se minha resposta ajude com seu problema que você marque o tópico como resolvido e escolha a melhor resposta!
Assim como seria de bom senso fazer o mesmo no tópico de 2018 já que lá resolveram o seu problema: https://www.vivaolinux.com.br/topico/C-C++/Como-faco-para-diferenciar-o-resultado-das-funcoes-stat-o...


4. Re: Problema passando parâmetro para OPENDIR()

Michel Dionisio Silva
micheldionisio

(usa Ubuntu)

Enviado em 02/02/2022 - 03:05h

Boa noite Heitor, te agradeço pela lembrança do tópico criado em 2018, realmente foi esquecimento meu sobre as boas práticas do fórum. Como você mesmo pode ver .. respondi os colegas em 1 dia útil da mesma forma que estou fazendo com você. E
além de informar que o problema foi resolvido, indiquei qual foi a técnica utilizada para solucionar o problema, então apesar de eu ter esquecido de marcar a melhor solução, quem leu até o final do tópico pode se beneficiar da solução implementada. De qualquer forma te agradeço pela lembrança, entrei no tópico que havia ficado em aberto e finalizei ele marcando a melhor resposta.
Esclarecido isso, vamos ao problema do momento.

Acredito que não consegui expor o problema de forma clara. A sugestão que você deu eu já testei e ja fiz funcionar das duas formas:
1ª - s = "/mnt/dados"; // É indiferente colocar / ou não no final. Ele vai identificar se é arquivo ou pasta do mesmo jeito!
2ª - // char s[50] = "/mnt/dados";

O problema não é a forma como eu armazeno o caminho antes de submeter para o opendir(), o problema é que não posso coloca-lo no código em "hard coded" como você fez nos dois exemplos. Por isso eu coloquei na descrição do problema: "Se eu coloco um texto fixo no opendir tudo funciona. Mas eu preciso trabalhar com uma variável porque o valor desse diretório está vindo de um arquivo de configuração que o aplicativo lê ao inicializar então tem que funcionar com variável.

O que eu quero dizer com "tem que funcionar com uma variável", é que

Se você reparar a saída da execução que eu coloquei no final do tópico mostra que eu testo a variável (char *s) desta implementação e o conteúdo está correto com o diretório que deve ser aberto pelo opendir(). Já fiz a mesma implementação utilizando s como (char s[50]) vetor de caracteres e também não funcionou. Resumindo sou obrigado a utilizar o strcpy() para armazenar o path do meu interesse dentro de s, seja ele ponteiro pra char ou vetor de char, porque o valor do path que preciso utilizar está dentro de uma variável.

O problema muito provavelmente está sim naquela linha de strcpy(), mas qual seria outra forma de fazer uma atribuição entre variáveis do tipo string em C sem utilizar o strcpy()

Quando executo:
// Montando caminho a ser trabalhado
strcpy(s,ctr->caminhoOrigem);
E testo logo a seguir o conteúdo de s com printf, o conteúdo está correto e é impresso corretamente no standard out, mas após o printf de validação do conteúdo eu submeto essa mesma variável s para o opendir() que falha com o erro 2, conforme mencionei acima no problema inicial.

Agradeço de qualquer forma o seu tempo Heitor e espero que tenha ficado mais claro o meu problema. Estou começando a achar que tem um bug no gcc ou tem alguma pegadinha no meu ambiente ubuntu.



5. Re: Problema passando parâmetro para OPENDIR()

Heitor Costa
Heitor.rj

(usa Slackware)

Enviado em 04/02/2022 - 18:03h

micheldionisio escreveu: Quando executo:
// Montando caminho a ser trabalhado
strcpy(s,ctr->caminhoOrigem);
E testo logo a seguir o conteúdo de s com printf, o conteúdo está correto e é impresso corretamente no standard out, mas após o printf de validação do conteúdo eu submeto essa mesma variável s para o opendir() que falha com o erro 2, conforme mencionei acima no problema inicial.

Esse é o ponto! O exemplo que dei serve pra esclarecer que "s" só irá funcionar se o valor dele for como as 2 formas abaixo, e que vc mesmo informa que ao testar estão corretas! Mas vc reparou se seu teste no printf pulou uma linha? Pq se o printf pulou linha tem caracter /n a mais na sua string!
s = "/teste/cripto/origem";
s = "/teste/cripto/origem/";

Paulo, na resposta acima, fala sobre isso! Se sua variável possue uma quebra de linha ela estaria sendo capturada assim:
s = "/teste/cripto/origem/\n"; // Dessa forma vai dar problema com Opendir() porque o caminho está errado! 
Então quando vc testar ela no terminal, verifique se printf não pulou a linha, pois se ele pulou é pq foi capturado o \n junto! O printf não pula linha no terminal!

Uma outra forma de testar é contar a qtd de caracteres de "s" no caminho acima seria 20 ou 21 Caracteres, logo se no teste der mais, tem coisa a mais que não deveria!
printf("%ld", strlen(ctr->caminhoOrigem)); // Precisa ser 20 se não tiver / no final ou 21 com a barra no final 
Paulo também explica na resposta dele sobre fgets() que SEMPRE captura \n caso seja dessa forma como vc está lendo seu arquivo, imaginando que esteja lendo linha a linha usando fgtes() e não caracter por caracter! Então neste caso, vc com certeza precisa remover do texto os caracteres que não devem fazer parte dele! Se estiver lendo caracter por caracter com o getc também terá que remover os caracteres que não farão parte de sua string. Vc também pode usar getline para ler linha a linha de um arquivo!

RESUMO: Muito provavelmente o problema é o /n ou /r/n sendo capturado com a string no código que vc lê o arquivo que não foi postado acima!

Se precisar de ajuda no Cod que lê a variável no arquivo, poste ele!

SENDO MAIS ESPECÍFICO:
printf("\n O nome do diretorio a ser aberto.: %s.", s); // \n Removido daqui
printf("TEXTO COLADO A VARIÁVEL S\n"); // Este texto vai ficar colado no seu caminho!

RESULTADO QUE TEM QUE SER:
/teste/cripto/origem/TEXTO COLADO A VARIÁVEL S

RESULTADO COM PROBLEMAS: Eles estarão em linhas separadas!
/teste/cripto/origem/
TEXTO COLADO A VARIÁVEL S

Logo se der o resultado errado é pq foi capturado a quebra de linha, e tem que consertar isso!


6. Re: Problema passando parâmetro para OPENDIR()

Paulo
paulo1205

(usa Ubuntu)

Enviado em 05/02/2022 - 01:39h

Heitor.rj escreveu:

Esse é o ponto! O exemplo que dei serve pra esclarecer que "s" só irá funcionar se o valor dele for como as 2 formas abaixo, e que vc mesmo informa que ao testar estão corretas! Mas vc reparou se seu teste no printf pulou uma linha? Pq se o printf pulou linha tem caracter /n a mais na sua string!
s = "/teste/cripto/origem";
s = "/teste/cripto/origem/";

Paulo, na resposta acima, fala sobre isso! Se sua variável possue uma quebra de linha ela estaria sendo capturada assim:
s = "/teste/cripto/origem/\n"; // Dessa forma vai dar problema com Opendir() porque o caminho está errado! 


Ele não está fazendo isso. Ele provavelmente recebe a quebra de linha do arquivo está lendo para saber o nome do diretório.

A não ser que você se refira ao que provavelmente seria o equivalente para produzir o mesmo resultado, caso o caminho não procedesse de um arquivo. Se você quis usar isso como analogia, talvez fosse melhor deixar mais clara essa intenção.

Então quando vc testar ela no terminal, verifique se printf não pulou a linha, pois se ele pulou é pq foi capturado o \n junto! O printf não pula linha no terminal!

Uma outra forma de testar é contar a qtd de caracteres de "s" no caminho acima seria 20 ou 21 Caracteres, logo se no teste der mais, tem coisa a mais que não deveria!
printf("%ld", strlen(ctr->caminhoOrigem)); // Precisa ser 20 se não tiver / no final ou 21 com a barra no final 


Uma correção: como strlen() retorna um valor do tipo size_t, a conversão a ser usada em printf() não seria "%ld", mas sim "%zu".
printf("%zu\n", strlen(ctr->caminhoOrigem)); 


Paulo também explica na resposta dele sobre fgets() que SEMPRE captura \n caso seja dessa forma como vc está lendo seu arquivo, imaginando que esteja lendo linha a linha usando fgtes() e não caracter por caracter! Então neste caso, vc com certeza precisa remover do texto os caracteres que não devem fazer parte dele! Se estiver lendo caracter por caracter com o getc também terá que remover os caracteres que não farão parte de sua string. Vc também pode usar getline para ler linha a linha de um arquivo!


Cuidado com a palavra “sempre” (ainda mais quando a escreve com todas as letras maiúsculas), pois há mais de uma possível situação em que a quebra de linha pode não ser capturada, mesmo que exista. O caso mais comum é quando ela não cabe no array de destino, mas outras situações podem incluir truncamentos do arquivo, erros de leitura ou a recepção de um sinal que interrompa prematuramente a chamada a read() subjacente a fgets().

RESUMO: Muito provavelmente o problema é o /n ou /r/n sendo capturado com a string no código que vc lê o arquivo que não foi postado acima!


Isso eu já tinha dito...

Se precisar de ajuda no Cod que lê a variável no arquivo, poste ele!

SENDO MAIS ESPECÍFICO:
printf("\n O nome do diretorio a ser aberto.: %s.", s); // \n Removido daqui 


Não precisava de remover a quebra de linha após o ponto, pois o próprio ponto, se aparecer a linha abaixo do nome do arquivo, já é suficiente para indicar que o nome do arquivo contém a quebra de linha. Tanto o é que bastou isso para que eu desse o diagnóstico de que esse é provavelmente o problema enfrentado pelo autor do tópico.


... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)


7. Re: Problema passando parâmetro para OPENDIR() [RESOLVIDO]

Michel Dionisio Silva
micheldionisio

(usa Ubuntu)

Enviado em 05/02/2022 - 21:10h


Olá Paulo1205, sua primeira resposta foi exata. Sim a função utilizada foi um fgets() e buscava linhas inteiras do arquivo com o infeliz do "\n" no final de cada linha lida. Eu fazia alguns testes mas achava que o opendir() saberia tratar a quebra de linha, mas ele só entende o "\0" que é final de string, o restante pra ele tudo faz parte da string. Agradeço o código exemplo Paulo, implementei o teu código de substituição do "\n" por "\0" logo que capturo a linha com o fgets() e tudo foi resolvido.
Agradeço ao colega Heitor do RJ que também não mediu esforços para analisar o problema.






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts