Материал: 6262

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

36

более точную семантику других полей следует изучать по руководству man.

Встандарте POSIX предусмотрены макросы, которые проверяют, является ли файл:

S_ISLNK(m) — символьной ссылкой;

S_ISREG(m) — обычным файлом;

S_ISDIR(m) — каталогом;

S_ISCHR(m) — символьным устройством;

S_ISBLK(m) — блочным устройством;

S_ISFIFO(m) — каналом FIFO;

S_ISSOCK(m) — сокетом.

Для поля st_mode, в стандарте POSIX для программирования на языке С предусмотрены также флаги, представленные в таблице 1.3.

Таблица 1.3 — Флаги для поля st_mode

S_IFMT

0170000

битовая маска для полей типа файла

S_IFSOCK

0140000

сокет

S_IFLNK

0120000

символьная ссылка

S_IFREG

0100000

обычный файл

S_IFBLK

0060000

блочное устройство

S_IFDIR

0040000

каталог

S_IFCHR

0020000

символьное устройство

S_IFIFO

0010000

канал FIFO

S_ISUID

0004000

бит setuid

S_ISGID

0002000

бит setgid

S_ISVTX

0001000

бит принадлежности

S_IRWXU

00700

маска для прав доступа пользователя

S_IRUSR

00400

пользователь имеет право чтения

S_IWUSR

00200

пользователь имеет право записи

S_IXUSR

00100

пользователь имеет право выполнения

S_IRWXG

00070

маска для прав доступа группы

S_IRGRP

00040

группа имеет права чтения

S_IWGRP

00020

группа имеет права записи

S_IXGRP

00010

группа имеет права выполнения

S_IRWXO

00007

маска прав доступа всех прочих (не находящихся в

 

 

группе)

S_IROTH

00004

все прочие имеют права чтения

S_IWOTH

00002

все прочие имеют права записи

S_IXOTH

00001

все прочие имеют права выполнения

37

Замечание

Обратите внимание на соответствие данной таблицы для поля st_mode и таблицы 4.10 для i_mode, приведенной в [4]. Учтите, что значения констант в этих таблицах приведены в разных представлениях.

В случае успеха, все функции возвращают ноль.

При обнаружении ошибки возвращается -1, а переменной errno присваивается номер ошибки:

EBADF - Неверный файловый описатель filedes;

ENOENT - Компонент полного имени файла file_name не существует или полное имя является пустой строкой;

ENOTDIR - Компонент пути не является каталогом;

ELOOP - При поиске файла встретилось слишком много символьных ссылок;

EFAULT - Некорректный адрес;

EACCES - Запрещен доступ;

ENOMEM - Недостаточно памяти в системе;

ENAMETOOLONG - Слишком длинное название файла.

Поскольку поля st_dev и st_rdev имеют тип dev_t, который может отличаться для разных аппаратных платформ, следует пользоваться макросами, присутсвующими в система разработки большинства ОС:

#define _BSD_SOURCE

/* See feature_test_macros(7) */

#include <sys/types.h>

 

dev_t makedev(unsigned int maj, unsigned int min); unsigned int major(dev_t dev);

unsigned int minor(dev_t dev);

Теперь рассмотрим конкретный пример, представленный на листинге 1.6 и демонстрирующий возможности изученных системных вызовов.

Листинг 1.6 — Запрос информации о статусе файлов

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

int main(int argc, char *argv[], char *envp[]) {

#define NO 0; #define YES 1;

// Переменные программы

 

 

struct stat

sb;

// Структура информации о файле

int res = NO;

// Состояние определения типа файла

char buf[255];

//

Буфер чтения данных имени файла

ssize_t n =

0L;

//

Чило прочитанных симвосов имени файла

38

puts("Программа lab1.5: Введи имя файла> "); n = read(0, buf, sizeof(buf));

if(n < 2) { // Нет аргумента - завершаем работу puts("\nОшибка: необходимо ввести имя_файла\n"); return 1;

}

buf[n - 1] = '\0';

printf("Исследуем

статус файла:

%s\n", buf);

printf("Длина

имени файла:

%lu\n", n - 1);

if (stat(buf, &sb) != 0){

printf("Ошибка получения статуса файла: %s", buf); return 1;

}

//Пример использования макросов определения типа файла res = S_ISDIR(sb.st_mode);

printf("%i\n", res);

//Другой вариант

printf("Файл %s является: ", buf);

 

switch (sb.st_mode &

S_IFMT) {

 

case S_IFBLK:

printf("блочным устройством\n");

break;

case S_IFCHR:

printf("символьным устройством\n");

break;

case S_IFDIR:

printf("директорией\n");

break;

case S_IFIFO:

printf("FIFO/pipe\n");

break;

case S_IFLNK:

printf("ссылкой на файл\n");

break;

case S_IFREG:

printf("обычным (регулярным) файлом\n"); break;

case S_IFSOCK:

printf("сокетом\n");

break;

default:

printf("неизвестным типом файла\n"); break;

}

 

 

 

 

 

printf("st_dev

=

0x%lx ( major = %u minor = %u )\n",

sb.st_dev, major(sb.st_dev), minor(sb.st_dev));

printf("st_rdev

=

0x%lx ( major = %u minor = %u )\n",

sb.st_rdev, major(sb.st_rdev), minor(sb.st_rdev));

printf("st_ino

=

%lu\n", sb.st_ino);

 

printf("st_mode

=

0%o\n", sb.st_mode);

 

printf("st_nlink

=

%lu\n", sb.st_nlink);

 

printf("st_size

=

%lu\n", sb.st_size);

 

printf("st_blksize =

%lu\n", sb.st_blksize);

 

printf("st_blocks

=

%lu\n", sb.

st_blocks

);

 

return EXIT_SUCCESS;

}

Вариант запуска данной программы представлен на рисунке 1.13.

Замечание

Программа, представленная на листинге 1.6, осуществляет ввод имени файла с клавиатуры, что позволяет легко исследовать статусы множества файлов, не выходя из системы разработки.

ОС УПК АСУ имеет утилиту с именем stat. Студенту следует самостоятельно изучить ее применение и сравнить полученные результаты с разработанной программой.

39

Рисунок 1.13 — Вариант запуска программы листинга 1.6

1.5 Каналы

Операционные системы предоставляют программисту два типа каналов:

полудуплексные каналы UNIX;

именованные каналы FIFO.

1.5.1Полудуплексные каналы UNIX

Изучая командный интерпретатор shell, мы уже сталкивались с понятием ка-налов. Например, если в командной строке запустить: ls -l | grep src, то интерпретатор sh или bash будут выполнять следующую последовательность действий:

будут одновременно запускатся утилиты ls, обеспечивающая вывод подроб-

ного списка файлов текущей директории, и утилита grep, фильтрующая входной поток данных по наличию слова src, в каждой строке;

перед вызовом утилит, shell создаст полудуплексный каканал, обеспечив возможность записи в него для утилиты ls и чтение из него для утилиты grep.

Каналы - старейший из инструментов IPC, существующий приблизительно со времени появления самых ранних версий оперативной системы UNIX. Они предоставляют метод односторонних коммуникаций между процессами: отсюда появился термин half-duplex channel.

Сам канал создается в ядре ОС. Когда процесс создает канал, ядро устанавливает два файловых дескриптора для пользования этим каналом. Один такой дескриптор используется, чтобы открыть путь ввода в канал (запись), в то время как другой применяется для получения данных из канала (чтение), как показано ниже:

 

40

in

<-----

Process

Kernel

out

----->

Если открыт массив дескрипторов int fd[2] и процесс посылает данные через канал fd[1], то он имеет возможность получить эту информацию из дескрип-тора fd[0].

Хотя подобное применение канала не имеет практической ценности, для учебных целей, показанных на листинге 1.7, оно вполне подходит.

Создание неименованного канала выполняется с помощью функции pipe(...):

#include <unistd.h>

int pipe(int pipefd[2]);

где pipefd — целочисленный массив открываемых дескрипторов канала.

Листинг 1.7 — Запись строки в ядро ОС и чтение из канала

#include <stdio.h> #include <stdlib.h> #include <unistd.h>

int main(void) { int fd[2];

char out[] = "Строка, записанная в канал...\n"; char buf[BUFSIZ];

if (pipe(fd) == -1) { perror("pipe"); exit(EXIT_FAILURE);

}

write(fd[1], out, sizeof(out)); // Пишем в канал close(fd[1]);

while(read(fd[0], buf, 1) > 0) write(1, buf, 1);

close(fd[0]);

return EXIT_SUCCESS;

}

Основное назначение неименованных полудуплексных каналов взаимодействие между родительским и дочерними процессами. В этом случае используется то свойство, что дочерний процесс наследует все ресурсы, открытые родительским процессом, в том числе и открытые каналы.

Если предположить, что родительский процесс долже передать некоторое сообщение дочернему процессу, а потом дождаться его завершения, то в этом случае:

родителскому процессу не нужет дескриптор чтения из канала;

дочернему процессу не нужен дескриптор записи в канал.

Источник: https://studfile.net/preview/16438530/