LINUX.ORG.RU

Использовать stat для проверки файла на существование.


0

0

Собственно сабж. Хотелось бы узнать можно ли использовать функцию stat для проверки того, существует файл или нет. Заранее спасибо тем, кто поможет. Не хочется просто access держать только для проверки файла на существование.

★★★

Последнее исправление: Dorif (всего исправлений: 1)

если только проверить, то access нужен.
если инфа о файле нужна, то можно и stat обойтись.
если открыть, то open.

rg-400
()

Почему нет. Но лучше сразу открывать его и пытаться читать, писать или что вам там надо делать. Если файл не существует или к нему нет доступа вы всё равно об этом узнаете. По-моему, это лучший способ.

undet
()
Ответ на: комментарий от undet

Просто хочется, чтобы все исключительные ситуации обрабатывались самой прогой. Поэтому интересует то. как проверить существует ли файл только с помощью stat(stat в проге юзается чаще и для разных целей, access только в нескольких местах и то для проверки того, существует ли файл) или ещё каким- то способом. без подключения unistd.h

Dorif ★★★
() автор топика
Ответ на: комментарий от rg-400

>смотришь значение errno.
Дополнение: errno должен быть равным ENOENT (man errno.h).

edigaryev ★★★★★
()

Ну узнаешь ты, что файл есть, потом сделаешь open и его уже не будет. Может сразу использовать open ?

Reset ★★★★★
()
Ответ на: комментарий от MuZHiK-2

цитирую тс:

stat в проге юзается чаще и для разных целей.


rg-400
()
Ответ на: комментарий от Reset

>Ну узнаешь ты, что файл есть, потом сделаешь open и его уже не будет. Может сразу использовать open ?

тс не говорил, что он хочет открывать файл.

rg-400
()
Ответ на: комментарий от Reset

Эммм.. Не верится, что эта ситуация может в норме произойти у пряморукого пользователя... Open сразу юзать нельзя- по задумке нужно сначала проверить права доступа и тип файла(Иначе на кой мне stat нужен был бы?).

Dorif ★★★
() автор топика
Ответ на: комментарий от Dorif

Ну узнаешь ты тип, а когда сделаешь open, то тип уже будет другой. Защита от дурака всегда должна быть, на основе таких вот ляпов обычно и ломают программы.

Reset ★★★★★
()
Ответ на: комментарий от Dorif

права доступа проверять не нужно.
в errno будет соответствующее значение (EACCES), если запрошенный доступ к файлу не разрешен.
Смотри другие значения ошибок в open(2), возможно, тебе не нужен stat.

rg-400
()
Ответ на: комментарий от Reset

Хорошо, а КАК тогда «зафиксировать» тип файла? И(если не сложно) предложи способы взлома(и пути устранения уязвимостей, делающих взлом возможным) вот этой проги:

#include <stdio.h>
#include <unistd.h>
//unistd.h is needed for access() function
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <string.h> 
struct stat b;
int help();
int main(int argc, char **argv)
{
	if(argc==3) if(!strcmp(argv[1],"-n")||!strcmp(argv[1],"--number"))
		{
		if(access(argv[2],0)==-1){
		printf("File %s does not exist or access to the directory, where file is located is denied.\n",argv[2]);
		return 1;
		}
		else if(access(argv[2],4)==-1){
		stat(argv[2],&b);
		printf("You don't have rights to read this file.\n"
		"Rights for this file:\n"
		"Access mode: %o\n"
		"Ownership: UID: %d GID: %d\n"
		"Last access time: %s\nLast status change time: %s\nLast change time: %s\n",b.st_mode,b.st_uid,b.st_gid,ctime(&b.st_atime),ctime(&b.st_mtime),ctime(&b.st_ctime));
		return 1;
		}
		else {
			stat(argv[2], &b);
			if(S_ISDIR(b.st_mode)){
				printf("File %s is a directory.\n",argv[2]);
				return 1;
			}
		}
		FILE *f=fopen(argv[2],"r");
		int a,i;
		i=1;
		printf("1:");
		while(feof(f)==0){
			a=fgetc(f);
			if(a=='\n'){
			long pos;
			pos=ftell(f);
			fseek(f,1,SEEK_CUR);
			if(fgetc(f)==EOF){
				putchar(a);
				fclose(f);
				return 0;
				}
			else printf("\n%d: ",++i);
			fseek(f,pos,SEEK_SET);
			}
		else putchar(a);
		}
	}
		else help();
	else if(argc==1||!strcmp(argv[1],"-h")||!strcmp(argv[1],"--help")) help();
	else{
		if(!strcmp(argv[1],"-v")||(!strcmp(argv[1],"--version"))){
		printf("cloncat version 0.3\n");
		return 0;
	}
	else{
	if(access(argv[1],0)==-1){
		printf("File %s does not exist or access to the directory, where file is located is denied.\n",argv[1]);
		return 1;
	}
	else if(access(argv[1],4)==-1){
		stat(argv[1],&b);
		printf("You don't have rights to read this file.\n"
		"Rights for this file:\n"
		"Access mode: %o\n"
		"Ownership: UID: %d GID: %d\n"
		"Last access time: %s\nLast status change time: %s\nLast change time: %s\n",b.st_mode,b.st_uid,b.st_gid,ctime(&b.st_atime),ctime(&b.st_mtime),ctime(&b.st_ctime));
		return 1;
	}
	else {
		stat(argv[1], &b);
		if(S_ISDIR(b.st_mode)){
			printf("File %s is a directory.\n",argv[1]);
			return 1;
		}
	}
		FILE *f=fopen(argv[1],"r");
		while(feof(f)==0){
			int a;
			a=fgetc(f);
			if(a=='\n'){
				long pos;
				pos=ftell(f);
				fseek(f,1,SEEK_CUR);
				if(fgetc(f)==EOF){
					putchar(a);
					fclose(f);
					return 0;
					}
				else putchar(a);
				fseek(f,pos,SEEK_SET);
			}
			else putchar(a);
		}
	}
}
}
int help(){
		printf("usage: cloncat filename\n"
		"-h or --help for help\n"
		"-v or --version displays version and exit\n");
		return 0;
	}

Dorif ★★★
() автор топика
Ответ на: комментарий от Dorif

1) есть такая штука getopt_long(для разбора опций).

2)

FILE *f=fopen(argv[1],"r"); 
feof(f)==0//если файла нет, то f==NULL..и 3,14..
3)повтор кода и не нужная внешняя переменная. и т.д.

rg-400
()
Ответ на: комментарий от rg-400

Хорошо: от этого кому- то становится хуже? *От того, что перед тем, как использовать функцию проверяется а можно ли её использовать и если нет, то она и не используется.

Dorif ★★★
() автор топика
Ответ на: комментарий от Dorif

мне интересно, а что должен делать этот код?
А то не очень понятен смысл магических чисел в выражения вроде этого:
access(argv[2],4)==-1)

rg-400
()
Ответ на: комментарий от Dorif

Open сразу юзать нельзя- по задумке нужно сначала проверить права доступа и тип файла.

open проверит права доступа, проверит существует ли файл. Чтобы проверить тип файла нужно прочитать хотя бы часть содержимого (или что подразумевается под типом файла?). Опять нужен open.

struct stat s;
int         fd;

fd = open("data/xyz.foo", O_RDONLY);
if (-1 == fd) {
    perror("open");
    exit(1);
    /* Или если очень хочется… */
    switch (errno) {
    case EACCES :
        fputs("You don't have rights to read this file\n", stderr);
        break;
    case ENOENT :
        fputs("File does not exist\n", stderr);
        break;
    }
    exit(1);
}

fstat(fd, &s);
if (s.st_mode & S_IFDIR) {
    fputs("File is a directory\n");
    exit(1);
}
undet
()
Ответ на: комментарий от rg-400

Проверка, есть ли право чтения. Если вместо 4 ноль- на существование. Откомментирую код завтра и выложу. Кстати, спасибо за идею превратить b в локальную переменную- чуть- чуть увеличит сорцы, но позволит избежать лишнего выделения памяти(переменной не выделится память. если она не используется).

Dorif ★★★
() автор топика
Ответ на: комментарий от Dorif

Делай f=fopen и проверяй открылся ли файл. Потом, если так уж нужно вызывать stat, то вызывай fstat для уже открытого файла. Это будет безопасно. access у тебя вообще непонятно зачем. Да и программа твоя в общем случае будет делать segmentation fault.

Reset ★★★★★
()
Ответ на: комментарий от Dorif
int
main(int argc, char **argv)
{
        struct stat st;
        if(argc > 1) {
                if (stat(argv[1], &st) == -1) {
                        printf("%s",strerror(errno));// или другая оработка.
                        return 1;
                }
        //здесь ваш код полезный код
        } else {
                printf("не хватило параметров!!");// или другая оработка.
                return 1;
        }
        
        return 0;
}
rg-400
()
Ответ на: комментарий от rg-400

1) есть такая штука getopt_long(для разбора опций).

Да можно и без него обойтись, достаточно завести переменные под все возможные опции, а потом сделать

for (int i = 0; i < argc; ++i)
{
   ....
   } else if (!strcmp(argv[i], "--option1") { 
      ....
   } else if (!strcmp(argv[i], "--option_with_arg") { 
      if (i == argc - 1) {
         usage();
      }
      // читаем argv[i + 1];
      ...
   }
   ...
}

всё проще и понятнее будет, чем эта лапша

Reset ★★★★★
()
Ответ на: комментарий от rg-400

Аналог cat'а стандартными средствами языка.

Dorif ★★★
() автор топика
Ответ на: комментарий от undet

fopen тоже всё проверит + получаем все плюшки от stdio в том числе буферизацию и форматированный ввод/вывод, fstat вызывать потом так

fstat(fileno(f), &s)

Reset ★★★★★
()
Ответ на: комментарий от rg-400

Если я правильно помню, память под зкакую- либо переменную выделяется при необходимости использования переменной(на протяжении работы функции, её использующей. По окончании работы функции локальная переменная уничтожается и освобождается выделенная ей память.)? Допустим в функции:

a(){
int b;
while(b<20)++b;
}
Переменная b существует(и ей выделяется память) только на протяжении работы функции a. Не так ли? Или я что- то пропустил?

Dorif ★★★
() автор топика
Ответ на: комментарий от Dorif

это правильно. Только функция main, в которой будет выделяется память для struct stat, будет работать до завершения программы.
А размер исходников никак не увеличится.

rg-400
()
Ответ на: комментарий от rg-400

Директории открываются как обычные файлы с простым O_RDONLY. Только при попытке что-то прочитать вылазит EISDIR.

undet
()
Ответ на: комментарий от Dorif

Ох шит, ну и лапша у тебя там... Только за то, КАК ты используешь access, я бы уже бил по рукам. Ну и даже подумать страшно о том, что будет при увеличении числа передаваемых опций (на этот счет можешь, например, посмотреть как это сделано в исходниках lrzip, что ли). То, как ты раскидал объявления всех переменных вперепешку с самим кодом - тоже тихий ужас, читать такие программы сложно. Вообще, неплохо про С написано у Кернигана.

MuZHiK-2 ★★★★
()
Ответ на: комментарий от undet

Ага, что-то я затупил. O_DIRECTORY не для этого. Ну тогда, что-то типа этого:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

int 
main(int argc, char **argv)
{
        char buf;
        int fd;
        
        fd = open(argv[1],O_RDONLY);//можно попробовать с O_WRONLY, O_RDWR
        
        if (fd == -1) {
                switch (errno) {
                case EISDIR:
                       fprintf(stderr, "%s - ссылается  на  каталог,"
                               " а тип доступа подразумевает запись\n",
                               argv[1]);
                       break;
                default:
                       fprintf(stderr, "не удалось олткрыть файл  - %s\n",
                               strerror(errno));
                }               
                return 1;
        }
        //тут может быть ваш цикл
        if (read(fd, &buf, 1) == -1) {     
                switch (errno) {
                case EISDIR:
                        fprintf(stderr, "%s - ссылается  на  каталог,"
                               " а  тип доступа подразумевает чтение\n",
                               argv[1]);
                        break;
                default:
                        fprintf(stderr, "не удалось прочитать - %s\n",
                                strerror(errno));
                }
                
                return 1;
        }
        
        printf("%c\n", buf);
        return 0;
}

rg-400
()
Ответ на: комментарий от Dorif

А это:

спасибо за идею превратить b в локальную переменную- чуть-чуть УВЕЛИЧИТ СОРЦЫ, но позволит избежать лишнего выделения памяти(переменной не выделится память. если она не используется).


п.с.:

хочешь уменьшить размер?

Тогда нужно подумать, зачем нужны функции,а после применять их, а не копировать и вставлять код.х

rg-400
()
Ответ на: комментарий от rg-400

Одна проблема- никак не могу понять, как вынести в отдельную функцию алгоритм, использующий argv. Выношу в отдельную функцию- орёт, что argv не определана.Может подскажете путь? А пока выкладываю новые сорцы:

#include <stdio.h>
#include <unistd.h>
//unistd.h is needed for access() function
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <string.h> 
int help();
int main(int argc, char **argv){
	if(argc==3) if(!strcmp(argv[1],"-n")||!strcmp(argv[1],"--number")){
		if(access(argv[2],0)==-1){
		printf("File %s does not exist or access to the directory, where file is located is denied.\n",argv[2]);
		return 1;
		}
		else if(access(argv[2],4)==-1){
			struct stat b;
			stat(argv[2],&b);
			printf("You don't have rights to read this file.\n"
			"Rights for this file:\n"
			"Access mode: %o\n"
			"Ownership: UID: %d GID: %d\n"
			"Last access time: %sLast status change time: %sLast change time: %s",b.st_mode,b.st_uid,b.st_gid,ctime(&b.st_atime),ctime(&b.st_mtime),ctime(&b.st_ctime));
			return 1;
			}
		else {
			struct stat b;
			stat(argv[2], &b);
			if(S_ISDIR(b.st_mode)){
				printf("File %s is a directory.\n",argv[2]);
				return 1;
			}
		}
		FILE *f=fopen(argv[2],"r");
		int a,i;
		i=1;
		printf("1:");
		while(feof(f)==0){
			a=fgetc(f);
			if(a=='\n'){
			long pos;
			pos=ftell(f);
			fseek(f,1,SEEK_CUR);
			if(fgetc(f)==EOF){
				putchar(a);
				fclose(f);
				return 0;
				}
			else printf("\n%d: ",++i);
			fseek(f,pos,SEEK_SET);
			}
		else putchar(a);
		}
	}
		else help();
	else if(argc==1||!strcmp(argv[1],"-h")||!strcmp(argv[1],"--help")) help();
	else{
		if(!strcmp(argv[1],"-v")||(!strcmp(argv[1],"--version"))){
		printf("cloncat version 0.3\n");
		return 0;
	}
	else{
	if(access(argv[1],0)==-1){
		printf("File %s does not exist or access to the directory, where file is located is denied.\n",argv[1]);
		return 1;
	}
	else if(access(argv[1],4)==-1){
		struct stat b;
		stat(argv[1],&b);
		printf("You don't have rights to read this file.\n"
		"Rights for this file:\n"
		"Access mode: %o\n"
		"Ownership: UID: %d GID: %d\n"
		"Last access time: %sLast status change time: %sLast change time: %s",b.st_mode,b.st_uid,b.st_gid,ctime(&b.st_atime),ctime(&b.st_mtime),ctime(&b.st_ctime));
		return 1;
	}
	else {
		struct stat b;
		stat(argv[1], &b);
		if(S_ISDIR(b.st_mode)){
		printf("File %s is a directory.\n",argv[1]);
		return 1;
		}
	}
		FILE *f=fopen(argv[1],"r");
		long pos;
		fseek(f,0,SEEK_END);
		pos=ftell(f)-1;
		fseek(f,0,SEEK_SET);
		for(int i;i<=pos;++i)putchar(fgetc(f));
		fclose(f);
		return 0;
	}
}
}
int help(){
		printf("usage: cloncat filename\n"
		"-h or --help for help\n"
		"-v or --version displays version and exit\n"
		"-n or --number number the output lines\n");
		return 0;
	}

Dorif ★★★
() автор топика
Ответ на: комментарий от Dorif

передать ее как параметр.

void
function_name(const char *name)
{
     printf("main name is %s\n",name);
}
int 
main(int argc, char **argv)
{
        function_name(argv[0]);
        return 0;
}
stat тебе никак не поможет undet же написал, как проверять права и проверять, что это не каталог.

rg-400
()
Ответ на: комментарий от rg-400

А если так сделать. то функция

void fchk(const char *fn){ 
	if(access(fn,0)==-1){
		printf("File %s does not exist or access to the directory, where file is located is denied.\n",fn);
		return 1;
		}
		else if(access(fn,4)==-1){
			struct stat b;
			stat(fn,&b);
			printf("You don't have rights to read this file.\n"
			"Rights for this file:\n"
			"Access mode: %o\n"
			"Ownership: UID: %d GID: %d\n"
			"Last access time: %sLast status change time: %sLast change time: %s",b.st_mode,b.st_uid,b.st_gid,ctime(&b.st_atime),ctime(&b.st_mtime),ctime(&b.st_ctime));
			return 1;
			}
		else {
			struct stat b;
			stat(fn, &b);
			if(S_ISDIR(b.st_mode)){
				printf("File %s is a directory.\n",fn);
				return 1;
			}
	}
}
вызовет предупреждение, что в void- функции возвращается значение. Меняю тип на int- орёт, что функция НЕ возвращает значения.))) И в обоих случаях использование проги по отношению к несуществующим файлам приводит к сегфолту... open юзать не хочется, ибо это низкоуровневая, т.е.- зависящая от ОС функция, а значит для переноса проги её придётся пусть и немного, но переписывать(В школе винды стоят... 98 и хрюндель.(дома венда не держится)). Поэтому прога написана так, как написана. Если есть идеи, как устранить сегфолт- поделитесь, пожалуйста, а пока буду юзать то, что работает.

Dorif ★★★
() автор топика
Ответ на: комментарий от Dorif

> open юзать не хочется, ибо это низкоуровневая, т.е.- зависящая от ОС функция

access() и stat() — тоже зависящие от ОС функции. В венде вроде есть какой-то слой совместимости с POSIX, но я не знаю насколько он толстый. Я бы не рассчитывал, что, например, stat() будет там работать.

undet
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.