char* path = argv[1];
int rval;
/* Проверка существования файла. */
rval = access(path, F_OK);
if (rval == 0)
printf("%s exists\n", path);
else {
if (errno == ENOENT)
printf("%s does not exist\n", path);
else if (errno == EACCES)
printf("%s is not accessible\n", path);
return 0;
}
/* Проверка права доступа. */
rval = access(path, R_OK);
if (rval == 0)
printf("%s is readable\n", path);
else
printf("%s is not readable (access denied)\n", path);
/* проверка права записи. */
rval = access(path, W_OK);
if (rval == 0)
printf("%s is writable\n", path);
else if (errno == EACCES)
printf("%s is not writable (access denied)\n", path);
else if (errno == EROFS)
printf("%s is not writable (read-only filesystem)\n",
path);
return 0;
}
Вот как, к примеру, проверить права доступа к файлу README
, расположенному на компакт-диске:
% ./check-access /mnt/cdrom/README
/mnt/cdrom/README exists
/mnt/cdrom/README is readable
/mnt/cdrom/README is not writable (read-only filesystem)
8.3. Функция fcntl(): блокировки и другие операции над файлами
Функция fcntl()
— это точка доступа к нескольким особым операциям над файлами. Первым аргументом функции является дескриптор файла, вторым указывается код операции. Для некоторых операций требуется также дополнительный, третий аргумент. В этом разделе описана наиболее распространенная операция, выполняемая с помощью функции fcntl()
: блокирование файлов.
Функция fcntl()
позволяет программе поставить на файл блокировку чтения иди записи. Это напоминает применение исключающих семафоров, которые описывались в главе 5, "Взаимодействие процессов". Блокировка чтения ставится на файл, доступный для чтения. Соответственно блокировка записи ставится на файл, доступный для записи. Несколько процессов могут удерживать блокировку чтения одного и того же файла, но только одному процессу разрешено ставить блокировку записи. Файл не может быть одновременно заблокирован и для чтения, и для записи. Учтите, что наличие блокировки не мешает другим процессам открывать файл и осуществлять чтение/запись его данных, если только они сами не попытаются вызвать функцию fcntl()
.
Прежде чем ставить блокировку на файл, необходимо создать и обнулить структуру типа flock
. В поле l_type
должна быть записана константа F_RDLCK
в случае блокировки чтения и константа F_WRLCK
— в случае блокировки записи. Далее следует вызвать функцию fcntl()
, передав ей дескриптор файла, код операции F_SETLCKW
и указатель на структуру типа flock
. Если аналогичная блокировка уже была поставлена другим процессом, функция fcntl()
перейдет в режим ожидания, пока "мешающая" ей блокировка не будет снята.
В листинге 8.2 показана программа, которая открывает для записи указанный файл, а затем ставит на него блокировку записи. Программа ждет нажатия клавиши , после чего снимает блокировку и закрывает файл.
Листинг 8.2. ( lock-file.c ) Установка блокировки записи с помощью функции fcntl()
#include
#include
#include
#include
int main(int argc, char* argv[]) {
char* file = argv[1];
int fd;
struct flock lock;
printf("opening %s\n", file);
/* Открытие файла. */
fd = open(file, O_WRONLY);
printf("locking\n");
/* инициализация структуры flock. */
memset(&lock, 0, sizeof(lock));
lock.l_type = F_WRLCK;
/* Установка блокировки записи. */
fcntl(fd, F_SETLKW, &lock);
printf("locked; hit Enter to unlock... ");
/* Ожидание нажатия клавиши . */
getchar();
printf("unlocking\n");
/* Снятие блокировки. */
lock.l_type = F_UNLCK;
fcntl(fd, F_SETLKW, &lock);
close(fd);
return 0;
}
Скомпилируйте программу и запустите ее с каким-нибудь тестовым файлом, скажем, /tmp/test-file
:
% cc -o lock-file lock-file.с
% touch /tmp/test-file
% ./lock-file /tmp/test-file
opening /tmp/test-file
locking
locked; hit Enter to unlock...
Теперь откройте другое окно и вызовите программу еще раз с тем же файлом:
% ./lock-file /tmp/test-file
opening /tmp/test-file
locking
Пытаясь поставить блокировку на файл, программа сама окажется заблокированной. Вернитесь в первое окно и нажмите :
unlocking
В результате программа, запущенная во втором окне, немедленно продолжит свою работу. Если необходимо, чтобы функция fcntl()
не переходила в режим ожидания в случае, когда блокировку поставить невозможно, задайте в качестве кода операции константу F_SETLCK
, а не F_SETLKW
. Если функция обнаружит, что запрашиваемый файл уже заблокирован, она немедленно вернет -1.
Читать дальше