|
Программирование >> Структура ядра и системные вызовы
fvar.l ien = 0; } /* пока есть блокировки, установленные другими процессамиу*/ } /* пока попытка блокирования не будет успешной */ /* файл заблокирован; теперь обработать данные в файле */ /* ... */ /* теперь снять блокировку со всего файла */ fvar.l type = F UNLCK; fvar.l whence = SEEK SET; fvar.l start =0; fvar.l len =0; if (fcntl(fdesc, F SEtLKW,Sfvar)==-1) perror( fcntl ) } return 0; } /* main */ В качестве аргументов в этой программе используется одно или несколько путевых имен. Для каждого из указанных файлов программа пытается с помощью функции fcntl установить рекомендуемую блокировку. Если вызов fcntl неудачен, программа просматривает файл и выводит информацию обо всех блокировках на стандартный вывод. В частности, для каждой заблокированной области программа сообщает: путевое имя файла; идентификатор процесса, который заблокировал область; начальный адрес заблокированной области; длину заблокированной области; вид блокировки: исключающая (блокировка записи) или разделяемая (блокировка чтения). Цикл выполняется до тех пор, пока вызов функции fcntl не будет выполнен успешно. После этого программа обрабатывает файл, а затем вызовом fcntl снимает с него блокировку. 7.3. API каталогов Файлы каталогов в UNIX- и POSIX-системах используются для того, чтобы помочь пользователям организовать свои файлы в некую структуру, соответствующую их назначению (например, все исходные тексты программы на С++ можно поместить в каталот /и$г/<имя программы>/0. Каталоги используются операционной системой также для преобразования путевых имен файлов в номера их индексных дескрипторов. В BSD UNIX и POSIX.l катштоги создаются с помощью API mkdir. #include <sys/stat.h> #include <uni5td.h> int nikdir ( const char* path name, mode t mode ): Аргумент path name - это путевое имя файла каталога, который нужно создать. Аргумент mode задает права доступа для владельца, группы и прочих пользователей, которые будут назначены этому файлу. Как и в API open, значение mode модифицируется значением umask вызывающего процесса. В случае успешного выполнения /пМ>возвращает О, а в случае неудачи - -1. Среди возможных причин неудачи следует назвать ошибку в аргументе path name, отсутствие у вызывающего процесса права на создание указанного каталога, ошибку в аргументе mode. В UNIX System V.3 для создания файлов каталогов используется API mknod. В UNIX System V.4 поддерживаются оба интерфейса, mkdir и mknodl Различие между ними состоит в том, что каталог, созданный функцией mknod, не содержит ссылок на текущий и родительский каталоги, поэтому его можно использовать только после того, как пользователь создаст эти ссылки явно. Одновременно с созданием каталога функцией mkdir появляются и ссылки на текущий и родительский каталоги, поэтому каталог можно использовать сразу же. Вообще-то говоря, mknod не следует применять для создания каталогов. А в системах, где не поддерживается API mkdir, каталоги можно создавать с помощью API system: char syscmd[256]; sprintf (syscmd, mkdir %s ,<имя каталога>); if (system (syscmd) == -1) perror ( mkdir ); Идентификатор владельца нового каталога устанавливается равным эффективному идентификатору процесса, его создавшего, а идентификатор группы нового каталога - равным эффективному идентификатору группы вызывающего процесса или идентификатору группы родительского процесса, владеющего новым каталогом (так же, как для обычных файлов). Каталог - это файл, содержащий записи, в каждой из которых хранится имя и номер индексного дескриптора файла, расположенного в этом каталоге. Структура записей каталога не во всех системах одинакова. Например, в UNIX System V записи каталога имеют фиксированную длину, а в BSD UNIX - переменную. Чтобы процесс мог просматривать каталоги независимо от файловой системы, запись каталога определена как struct dirent в заголовке <dirent.h> (в UNIX System V и POSIX.l) и как struct direct в заголовке <sys/dir.h> (в BSD UNIX 4.2 и 4.3). Типы данных struct dirent и struct direct имеют одно общее поле, d name, представляющее собой массив символов, который содержит имя файла, находящегося в каталоге. Для ускоренного просмотра каталогов созданы переносимые функции, определенные в заголовках <dirent.h> и <sys/dir.h>. #include <sys/types.h> #if defined (BSD) && ! POSIX SOURCE #include <sys/dir.h> typedef struct direct Dirent; #else #include <dirent.h> typedef stuct dirent Dirent; #endif DIR* opendir (const char* path name); Dirent* readdir (DIR* dir fdesc); int dosedir (DIR* dir fdesc); void rewinddir (DIR* dir fdesc); Использование этих функций описано ниже. Функция Назначение opendir Открывает файл каталога только для чтения. Возвращает указатель на структуру DIR* для последующих обращений к файлу readdir Читает запись из файла каталога, обозначенного аргументом dir Jdesc, и возвращает содержащуюся в ней информацию dosedir Закрывает файл, обозначенный аргументом dirJdesc rewinddir Устанавливает указатель чтения в начало файла каталога, обозначенного аргументом dir Jdesc. Следующий вызов readdir прочитает первую запись из этого файла Функция opendir аналогична API open. В качестве аргумента она принимает путевое имя файла каталога и открывает этот файл только для чтения. Данная функция возвращает указатель на структуру DIR*, которая используется приблизительно так же, как указатель на структуру FILE*, возвращаемый функцией fopen. Структура данных DIR определена в заголовке <dirent.h> или <sys/dir.h>. Функция readdir читает следующую (относительно текущей позиции указателя) запись из файла каталога, обозначенного аргументом dirJdesc. Значение dirJdesc - это значение DIR*, возвращенное вызовом opendir Данная функция возвращает адрес записи типа struct dirent или struct direct, в которой хранится имя файла. Когда readdir вызывается после API opendir или rewinddir, она возвращает указатель на первую запись данных из файла, при следующем вызове - на вторую запись и т.д. Просмотрев все записи в файле каталога, readdir возвращает нулевое значение, показывая тем самым, что достигнут конец файла. Отметим, что тип данных Dirent определяется в вышеприведенном прототипе либо как struct dirent (для POSIX и UNIX System V), либо как struct direct (для BSD UNIX в POSIX-несовместимом режиме). Благодаря этому любое приложение, вызывающее readdir, может трактовать возвращаемое значение как Dirent независимо от системы, в которой оно работает. Функция dosedir аналогична API close. Она закрывает соединение между указателем dir Jdesc и файлом каталога. Функция rewinddir сбрасывает указатель чтения, связанный с файлом dir Jdesc, так, чтобы при следующем вызове readdir эта функция могла просматривать данный каталог (обозначенный аргументом dir Jdesc) с начала. В UNIX-системах (System V и BSD UNIX) определены дополнительные функции для произвольной выборки записей файлов каталогов. Стандартом POSIX. 1 эти функции не поддерживаются. Функция Назначение telldir Возвращает указатель на текущую позицию в файле, заданном аргу- ментом dirJdesc seekdir Изменяет указатель текущей позиции в файле, заданном аргументом dir Jdesc, на указанный адрес Удаление файлов каталогов производится с помошью API rmdir. При наличии статуса привилегированного пользователя можно удалять каталоги с помошью API unlink. Эти API требуют, чтобы удаляемые каталоги были пустыми, т.е. не содержали никаких файлов, кроме ссылок на текущий и родительский каталоги. Прототип функции rmdir выглядит следующим образом: #include <unistd.h> int rmdir (const char* path name); Ниже приведена программа listdir. С, которая иллюстрирует использование API mkdir, opendir, readdir, dosedir и rmdir ♦include <iostream.h> ♦include <stdio.h> ♦ include <sys/types.T ♦ include <unistd.h> ifi : ♦include <fcntl.h> ♦include <string.h> ♦include <sys/stat.h> ♦if defined (BSD) && ! P0SIX SOURCE ♦include <sys/dir.h> typedef struct direct Dirent; ♦else ♦include <dirent.h> typedef struct dirent Dirent; ♦endif int main (int argc, char* argv[]) Dirent* dp; DIR* dir fdesc; . . while (-argc > 0) { /* вьтолнить следующее для казкдого файла */ if (! (dir fdesc=opendir(*++argv) 1 ) { .Klif (mkdir(*argv, S IRWXUIS IRWXGIS IRWXO)==-1) , > \ perror ( opendir ) ; j.ijcontinue; /* просмотреть каждый файл каталога дважды */ int i = 0; for ( ; i < 2; i++) { - Ints cnt = 0; . for (; dp=readdir(dir fdesc); ) cout dp->d name endl; if (strcmp(dp->d name, . ) && strcmp(dp->d name, .. )) Gnt++; . /* подсчитать количество файлоа в каталоге */ if (!cnt) { rmdir(*argv); break; }/* пустой каталог */ rewinddir (dir fdesc) ; /* сбросить указатель дпя второго цикла */ ) - closedir(dir fdesc> f ) /* для каждого файла */ return 0; } /* main */ В качестве аргументов эта программа принимает один или несколько путевых имен файлов каталогов. Для каждого аргумента программа выполняет указанные ниже операции. Вначале она открывает его вызовом opendir и присваивает значение указателя позиции в файле переменной dirjdesc. Если вызов opendir неудачен, программа считает, что данного каталога не существует, и пробует создать его с помощью API mkdir. Если opendir выполняется успещно, программа просматривает файл каталога с помощью API readdir и определяет число файлов в нем (без учета файлов . и .. ). Затем, если каталог пуст, программа удаляет его при помощи API rmdir. Если в каталоге есть файлы, то программа с помощью rewinddir сбрасывает указатель файла, связанный с dirjdesc, а затем просматривает каталог-вторично и выводит имена всех находящихся в нем файлов на стандартный вывод. По заверщении второго цикла просмотра каталога программа закрывает dir Jdesc с помощью API closedir. 7Л, API файлов устройств Файлы устройств используются для сопряжения физических устройств (например, консоли, модема, дисковода) с прикладными программами. Когда процесс читает файл устройства или записывает в него данные, ядро на основании старщего и младщего номеров устройства выбирает драйвер ДЛЯ выполнения фактической пересылки данных. Файлы устройств бывают байт-ориентированными и блок-ориентированными. Поддержка файлов устройств зависит от реализации ОС. В стандарте POSIX.l порядок создания файлов устройств не оговаривается. В UNIX-системах для создания файлов устройств применяется API mknod: #include <sys/stat.h> #include <unistd.h> int mknod (const char* path name, mode t mode, int device id); Аргумент path name - это путевое имя файла устройства, который нужно создать. Аргумент mode задает права доступа к создаваемому файлу для владельца, группы и прочих пользователей, а также устанавливает флаги S IFCHR или S IFBLK. Флаги служат для обозначения типа файла устройства (байт-ориентированный или блок-ориентированный). Права доступа модифицируются значением umask вызывающего процесса. Наконец, аргумент deviceJd содержит старший и младший номера устройств и в большинстве UNIX-систем строится следующим образом: младший байт deviceid устанавливается равным младшему номеру устройства, а следующий байт - равным старшему номеру устройства. Например, чтобы создать блок-ориентированный файл устройства SCSI5 со старшим номером 15, младшим номером 3 и правами доступа на чтение, запись и выполнение для всех пользователей, нужно применить следующий системный вызов mknod: mknod( SCSI5 , S IFBLK S IRWXU S IRWXG S IRWXO, (15 8)3); В UNIX System V.4 старший и младший номера устройства расширены соответственно до 14 и 18 битов. Старший и младший номера устройства используются следующим образом. Когда процесс читает данные из файла устройства или записывает данные в этот файл, с помощью старшего номера устройства файла производится поиск и вызов драйвера устройства, который выполняет фактический обмен данными с физическим устройством. Младший номер устройства - это аргумент, передаваемый в драйвер устройства при его вызове. Он необходим потому, что драйвер устройства может применяться для устройств различных типов, и младший номер задает параметры (например, размер буфера), которые должны использоваться для организации доступа к конкретному устройству. API mknod должен вызываться процессом с правами привилегированного пользователя. Идентификатор владельца и идентификатор группы для файла устройства назначаются так же, как для обычного файла. Атрибут размер файла для файла устройства смысла не имеет. В случае успешного выполнения функция mknod возвращает О, а в случае неудачи возвращает -1. Среди возможных причин неудачи можно выделить ошибку в путевом имени, отсутствие у процесса права на создание файла устройства, ошибку в аргументе mode.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |