Отримання даних про відкриті файли



 

Над дескрипторами файлів теж можна виконувати деякі операції, наприклад, відкривати файли, дублюючи дескриптори відкритих файлів, отримувати або встановлювати прапори, що описують стан дескриптора, захоплювати блоки файлу і так далі Всі ці операції виконуються функцією fcntl.

   #include <fcntl.h>

   int fcntl (int fd, int cmd, arg)

 

Функція виконує команду cmd над дескриптором файлу fd.

Деякі команди вимагають завдання додаткових аргументів.

 

Таблиця 3

Основні команди cmd

F_DUPFD Дублювання дескриптора файлу. Повертає інший дескриптор, що асоціюється з тим же відкритим файлом;
F_GETFD Отримує прапори, що асоціюються з дескриптором;
F_SETFD Встановлює прапори, що асоціюються з дескриптором;
F_GETFL Отримує прапори, що асоціюються з відкритим файлом;
F_SETFL Встановлює прапори, що асоціюються з відкритим файлом;
F_GETLK Отримує інформацію про захоплені області файлу;
F_SETLK Встановлює або скидає захоплення файлу;
F_SETLKW Ідентично F_SETLK, але чекає закінчення виконання;
F_GETOWN Отримує процес або групу процесів, яким буде посланий сигнал SIGIO
F_SETOWN Встановлює процес або групу процесів, яким буде посланий сигнал SIGIO

Діагностика

При успішному завершенні системного виклику залежно від операції cmd повертаються наступні значення:

F_DUPFD Новий дескриптор файлу.

F_GETFD Значення прапора (визначений тільки молодший біт).

F_SETFD Значення, відмінне від -1.

F_GETFL Значення прапорів статусу файлу.

F_SETFL Значення, відмінне від -1.

F_GETLK Значення, відмінне від -1.

F_SETLK Значення, відмінне від -1.

F_SETLKW Значення, відмінне від -1.

У разі помилки повертається -1, а змінною errno привласнюється код помилки.

 

Отримання і установка прапора стану файлу

 

1) Як по дескриптору файлу дізнатися, відкритий він на читання, запис, читання і запис одночасно?

int flags;

if((flags=fcntl (fd, F_GETFL, NULL)) < 0 )

return NULL; /* fd ймовірно не відкритий */

flags &= O_RDONLY | O_WRONLY | O_RDWR;

switch(flags){

case O_RDONLY: return "r";

case O_WRONLY: return "w";

case O_RDWR: return "r+w";

default: return NULL;

}

 

2) приклад зміни прапора дескриптора:

int flags = fcntl (fd, F_GETFL, 0);

fcntl (fd, F_SETFL, flags | O_NONBLOCK);

 

3) установка нового власника

fcntl(fd, F_SETOWN, getpid())

 

4) setflag (int desc, int value)

{

 int oldflags = fcntl (desc, F_GETFL, 0);

/* якщо відбулася помилка, виходимо з програми */

if (oldflags == -1)

return -1;

/* встановлюємо тільки потрібний прапор */

if (value != 0)

    oldflags |= O_NONBLOCK;

else

oldflags &= ~O_NONBLOCK;

/* зберігаємо прапор в дескрипторі файлу */

return fcntl (desc, F_SETFL, oldflags);

}

 

Передається два параметри: дескриптор і індикатор – 0, якщо треба зняти прапор і не 0, якщо встановити.

|= додає ?=~ знімає ~ інвертує

Зберігаємо в дескрипторі, повертаємо в зухвалу процедуру.

Блокування файлів з використанням fcntl

 

Окрім модифікації файлового дескриптора системний виклик fcntl(2) використовується для блокування файлу. Блокування областей файлу дозволяє декільком програмам спільно працювати з вмістом одного і того ж файлу, не заважаючи один одному.

Прикладом ситуації, в якій може бути корисний захоплення файлу служить бути програма, яка може бути запущена декількома користувачами незалежно, записує протокол роботи у файл. Декілька процесів, що одночасно записують інформацію у файл можуть зміщувати інформацію різних користувачів, що приведе до плутанини. У разі захоплення файлу цього не відбудеться.

В цьому випадку cmd - тип блокуючої операції, а в у arg указується адреса структури flock, в яку записується інформація про блокування. Структура і відповідні макроси описані в заголовному файлі <fcntl.h>.

 

Таблиця 4

Опис полий структури flock

Поле      Значення
short l_type                Тип блокування: записи – F_RDLCK, читання – F_WRLCK, скидання – F_UNLCK.
short l_whence Адреса початку ділянки, що блокується; дається у вигляді зсуву відносно початку файлу (0), щодо                          поточної позиції покажчика (1), щодо кінця файлу (2)

 

Продовження таблиці 4

Поле      Значення
long l_start Зсув в байтах, що інтерпретується відповідно до значення l_whence
long l_len Довжина ділянки, що блокується, в байтах. Якщо вказаний 0, блокується ділянка від l_start до кінця файлу
long l_pid Ідентифікатор процесу, що встановив блокування (для GETLCK)
long l_sysid Ссистемний ідентифікатор процесу, блокуючого файл

 

Якщо задана область вже заблокована, fcntl повертає -1.

За допомогою команди F_GETLK можна дізнатися, ідентифікатор процесу, що заблокував дану область.

Ядро автоматично знімає блокування, встановлені процесом, при закритті файлу.

За допомогою цієї функції можна маніпулювати дескрипторами файлів і встановлювати рекомендаційні (advisory) блокування (необов'язкові). В цьому випадку, якщо програма сама не використовує блокувань, блокування, встановлені іншими програмами, не матимуть для неї ніякого ефекту. Існує можливість додати рекомендаційним блокуванням fcntl() обов'язковий характер, але для цього відповідна файлова система повинна бути змонтована із спеціальним ключем.

 

Базові правила використання блокувань:

− Програми, які хочуть читати з файлу, належний відкрити файл, а потім використовувати fcntl в режимі F_RDLCK

− Програми, які хочуть читати з файлу і записувати у файл повинні відкрити файл, а потім використовувати flock в режимі F_WRLCK.

− Виклик flock блокуватиме файл до тих пір, поки він доступний, в цей час необхідні операції можуть бути виконані з деякою мірою безпеки.

− Після виконання операцій приберіть блокування шляхом закриття файлового дескриптора або за допомогою F_UNLCK

 

Приклад

1. Для установки блокування ми заповнюємо поля структури flock необхідними значеннями і викликаємо fcntl() з командою F_SETLK (встановити блокування):

..

struct flock fi;

fd=open(file, O_RDWR);

fi.l_type = F_WRLCK;

fi.l_whence = SEEK_SET;

fi.l_start = 0;

fi.l_len = 64;

off = 0;

while (fcntl(fd, F_SETLK &fi)== -1)

{ fcntl(fd, F_GETLK & fi);

...

printf("байти %i - %i заблоковані процесом %i\n", off, off+64

fi.l_pid);

}

 

Якщо задана область вже заблокована, fcntl повертає -1. За допомогою команди F_GETLK можна дізнатися, ідентифікатор процесу, що заблокував дану область.

 

2. Для того, щоб зняти блокування, ми викликаємо fctnl() з командою F_SETLK (дивно, чи не так?) і параметром l_type = F_UNLCK:

fi.l_type = F_UNLCK;

if (fcntl(fd, F_SETLK &fi)== -1)

printf("Помилка разблокирования\n");

Індівідуальні завдання

1. Написати програму, яка виводить дату і час останньої зміни файлу. Ім'я файлу задавати у вигляді аргументу командного рядка. Перевіряти, чи не виникають помилки при системних викликах.

2. Написати функцію, що додає право на читання файлу всім категоріям користувачів. Аргументом є колійне ім'я файлу. Функція повертає значення 0, якщо операція вдалася, і -1 в іншому випадку

3. Написати функцію, що визначає власника файлу. Аргументом функції є колійне ім'я файлу. Функція повертає ідентифікатор власника, у випадку успіху і -1 в іншому випадку.

4. Написати програму, що додає право читання файлу всім категоріям користувачів для декількох файлів. Імена файлів задавати у вигляді аргументів командного рядка. Перевіряти, чи не виникають помилки при системних викликах.

5. Написати функцію, що визначає, чи є право читати користувачеві заданий файл? Аргументом є колійне ім'я файлу. Функция возвращает значение 0, если такое право есть, и -1 в противном случае.

6. Написать функцию, определяющую, установлен ли бит смены идентификатора пользователя (S_ISUID) ? Аргументом является путевое имя файла. Функция возвращает значение 0, если это так, и -1 в противном случае.

7. Написать функцию, определяющую, является ли заданный файл символической ссылкой? Аргументом является путевое имя файла. Функция возвращает значение 0, если является, и -1 в противном случае.

8. Написать функцию, возвращающую длину файла. Аргументом функции является файловый дескриптор.

9. Открыть файл, указанный в командной строке, и выдать на экран параметры доступа к открытому файлу. Написать функцию, принимающую на входе файловый дескриптор и снимающую флаг, дающий право на запись в соответствующий файл, если он установлен. Проверить действие этого флага до и после снятия, вывести отчет на экран.

10. Определить, будет ли создаваться файл, указанный в командной строке, при программном обращении к нему. Вывести результат проверки на экран.

11. Написать функцию, принимающую на входе файловый дескриптор и определяющую, как при записи будут помещаться данные в соответствующий файл: в конец либо в начало. Выдать результаты проверки на экран.

12. Написать функцию, принимающую на входе файловый дескриптор и снимающую флаг O_NONBLOCK для соответствующего файла. Проверить действие этого флага до и после снятия, вывести результаты проверки на экран.

 


Дата добавления: 2018-04-05; просмотров: 431; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!