Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторная ОС_4.doc
Скачиваний:
9
Добавлен:
13.03.2016
Размер:
71.68 Кб
Скачать

Функции для работы с файловой системой

Возвращают дескриптор файла

Преобразуют имя в описатель

Назначают inode

Работают с атрибутами

Ввод/вывод из файла

Работают со структурой ФС

Управляют деревьями

Open, creat, dup, pipe, close

Open, creat, chdir, chmod, stat, mkfifo, mound, mknod, link, unmount, unlink, chown

Creat, link, unlink, mknod

Chown, chmod, stat

Read, write, lseek

Mount, unmount

Chmod, chown

Остановимся на тех из них, которые требуются для выполнения лабораторной работы. Для получения информации о типе файла необходимо воспользоваться системными вызовами stat() (fstat()). Формат системных вызовов stat() (fstat()):

#include <sys/types.h>

#include <sys/stat.h>

int stat(const char *name, struct stat *stbuf)

int fstat(int fd, struct stat *stbuf)

Оба системных вызова помещают информацию о файле (в первом случае специфицированным именем name, а во втором - дескриптором файла fd) в структурную переменную, на которую указывает stbuf. Вызывающая функция должна позаботиться о резервировании места для возвращаемой информации; в случае успеха возвращается 0, в противном случае -1 и код ошибки в errno. Описание структуры stat содержится в файле <sys/stat.h>. С небольшими модификациями она имеет вид:

struct stat

{

dev_t st_dev; /* device file */

ino_t st_ino; /* file serial inode */

ushort st_mode; /* file mode */

short st_nlink; /* number of links */

ushort st_uid; /* user ID */

ushort st_gid; /* group ID */

dev_t st_rdev; /* device ident */

off_t st_size; /* size of file */

time_t st_atime; /* last access time */

time_t st_mtime; /* last modify time */

time_t st_ctime; /* last status change */

}

Поле st_mode структуры stat содержит флаги, описывающие файл. Флаги несут следующую информацию:

S_IFMT 0170000 - тип файла

S_IFDIR 0040000 - каталог

S_IFCHR 0020000 - байт-ориентированный специальный файл

S_IFBLK 0060000 - блок-ориентированный специальный файл

S_IFREG 0100000 - обычный файл

S_IFFIFO 0010000 - дисциплина FIFO

S_ISUID 04000 - идентификатор владельца

S_ISGID 02000 - идентификатор группы

S_ISVTX 01000 - сохранить свопируемый текст

S_ISREAD 00400 - владельцу разрешено чтение

S_IWRITE 00200 - владельцу разрешена запись

S_IEXEC 00100 - владельцу разрешено выполнение.

Символьные константы, четыре первых символа которых совпадают с контекстом S_IF, могут быть использованы для определения типа файла.

Большинство системных вызовов, работающих с каталогами, оперируют структурой dirent, определенной в заголовочном файле <dirent.h>

struct dirent

{

ino_t d_ino; /* номер индексного дескриптора */

char d_name[DIRSIZ]; /* имя файла */

}

Еслифайл был стерт, то в поле d_ino записи каталога будет содержаться 0 (именно поэтому I-узлы нумеруются начиная с 1, а не с 0). При удалении файла содержимое его (блоки) уничтожается, I-узел освобождается, но имя в каталоге не затирается физически, а просто помечается как стертое: d_ino=0; поэтому имена с d_ino==0 - это имена уже уничтоженных файлов.

При создании нового имени (creat, link, mknod) система просматривает каталог и использует первый от начала свободный слот (ячейку каталога) где d_ino==0, записывая новое имя в него (только в этот момент старое имя окончательно исчезнет физически). Если пустых мест нет - каталог удлиняется.

Любой каталог всегда содержит два стандартных имени: "." - ссылка на текущий каталог (на его собственный I-node), ".." - на вышележащий каталог. У корневого каталога "/" оба этих имени ссылаются на него самого (т.е. содержат d_ino==2).

Имя каталога не содержится в нем самом. Оно содержится в родительском каталоге "..".

Создание каталога выполняется системным вызовом mkdir():

#include <sys/types.h>

#include <sys/stat.h>

int mkdir (char *pathname, mode_t mode);

При удалении каталога необходимо выполнить системный вызов rmdir().

#include <unistd.h>

int rmdir (char *pathname);

Открытие и закрытие каталога выполняется системными вызовами opendir() и closedir():

#include <sys/types.h>

#include <dirent.h>

DIR *opendir (char *dirname);

При успешном открытии каталога системный вызов возвращает указатель на переменную типа DIR, являющуюся дескриптором каталога, определенную в файле <dirent.h> и используемую при чтении и записи в каталог. При неудачном вызове возвращается значение NULL.

#include <dirent.h>

int closedir (DIR *dirptr); где dirptr - дескриптор каталога.

Для смены каталога служит системный вызов chdir():

#include <unistd.h>

int chdir (char *pathname);

Чтение записей каталога выполняется системным вызовом readdir():

#include <sys/types.h>

#include <dirent.h>

struct dirent *readdir (DIR *dirptr);

Системный вызов readdir() по номеру дескриптора каталога возвращает очередную запись из каталога в структуру dirent, либо нулевой указатель при достижении конца каталога. При успешном чтении, указатель каталога перемещается к следующей записи.

Дополнительный системный вызов

void rewinddir (DIR *dirptr);

переводит указатель каталога к первой записи каталога.

Функция getcwd получает полное имя текущего рабочего

каталога и запоминает его в pathbuf. Целый аргумент n определяет максимальную длину для имени директории. Возникает ошибка, если длина имени каталога, включая нулевой символ окончания, превышает n.

#include <direct.h>

char *getcwd(pathbuf,n);

Здесь char *pathbuf - память для path-имени, int n - максимальная длина имени.

Аргумент pathbuf может быть NULL; буфер размером n будет автоматически захватываться посредством malloc и использоваться для хранения path-имени.

Функция getcwd возвращает pathbuf. Возвращаемое значение NULL свидетельствует об ошибке и errno устанавливается в одно из следующих значений:

Значение Его смысл

ENOMEM Памяти недостаточно для размещения n

байт (когда аргумент NULL задан как pathbuf).

ERANGE Path-имя длинее, чем n символов.

Для разработки программы необходимо использовать компилятор GCC (GNU Compiler Collection), который входит в дистрибутив UNIX. Для создания исходного кода программ можно воспользоваться любым текстовым редактором (ee, vi и т.д.). После создания файла его необходимо сохранить с расширением .c, затем с консоли набрать команду gcc 1.c (вместо 1.с имя Вашего файла). После этого в каталоге должен появиться файл a.out, который необходимо запустить, чтобы просмотреть результаты работы программы, для этого выполните команду: ./a.out. Компилятор gсс по умолчанию присваивает всем созданным исполняемым файлам имя a.out. Если Вы хотите назвать его по-другому, нужно к команде на компиляцию добавить флаг -o и имя, которым необходимо назвать исполняемый файл: gсс 1.c –o primer. После чего в каталоге появится файл primer, который необходимо выполнить командой ./primer.

Пример программы, которая просматривает текущий каталог и записывает в файл имена всех встретившихся в нем файлов и каталогов:

//Подключение библиотек

#include <stdio.h>

#include <string.h>

#include <errno.h>

#include <dirent.h>

 

// Объявление констант имени просматриваемого каталога и файла для записи результата

#define DIRNAME "."

#define OFNAME  "out.log"

 

int main(void)

{

    FILE *ofp;

    DIR *dp;

    struct dirent *dent;

 

    if( (dp = opendir(DIRNAME)) == NULL) {

//Если открыть каталог не удалось, выводим в файл сообщение об ошибке и возвращаем код возврата равный 1

        fprintf(stderr, "opendir: %s: %s\n", DIRNAME, strerror(errno));

        return 1;

    }

    if( (ofp = fopen(OFNAME, "w")) == NULL) {

        fprintf(stderr, "fopen: %s: %s\n", OFNAME, strerror(errno));

        return 1;

    }

 

// построчно считываем имена файлов из каталога

    while(dent = readdir(dp))

// проверка, что имя каталога не равно «.» и «..»

// функция strcmp возвращает 0, если значения сравниваемых строк совпадают

        if(strcmp(".", dent->d_name) && strcmp("..", dent->d_name))

//записываем имя каталога в файл

            fprintf(ofp, "%s\n", dent->d_name);

    closedir(dp);

    fclose(ofp);

    return 0; //код возврата равен 0, функция выполнена без ошибок

}