44: if (flags & EXT3_APPEND_FL) printf("Append");
45: if (flags & EXT3_IMMUTABLE_FL) printf("Immutable");
46: if (flags & EXT3_SYNC_FL) printf("Sync");
47: if (flags & EXT3_NODUMP_FL) printf("Nodump");
48:
49: printf("n");
50: close(fd);
51: }
52:
53: return 0;
54: }
Ниже приведена похожая программа, которая устанавливает расширенные атрибуты ext3 для указанного списка файлов. Первый параметр должен быть списком флагов, которые нужно установить. Каждый флаг представляется в списке в виде одной буквы: А — только для добавления (append only), I — неизменяемый (immutable), S — синхронизированный (sync), N — недампированный (nodump). Эта программа не модифицирует существующие флаги файла; она только устанавливает флаги, переданные в командной строке.
1: /* setflags.c */
2:
3: /* Первый параметр этой программы — строка, состоящая из
4: 0 (допускается пустая) или более букв из набора I, A, S,
5: N. Эта строка указывает, какие из атрибутов ext3 должны
6: быть включены для файлов, указанных в остальных
7: параметрах командной строки — остальные атрибуты выключаются
8: буквы обозначают соответственно: immutable, append-only, sync и nodump.
9:
10: Например, команда "setflags IN file1, file2" включает
11: флаги immutable и nodump для файлов file1 и file2, но отключает
12: флаги sync и append-only для этих файлов. */
13:
14: #include <errno.h>
15: #include <fcntl.h>
16: #include <linux/ext3_fs.h>
17: #include <stdio.h>
18: #include <string.h>
19: #include <sys/ioctl.h>
20: #include <unistd.h>
21:
22: int main(int argc, const char **argv) {
23: const char **filename = argv + 1;
24: int fd;
25: int flags = 0;
26:
27: /* Убедиться, что указаны устанавливаемые флаги, вместе
28: с именами файлов. Позволить установить "0", как признак
29: того, что все флаги должны быть сброшены. */
30: if (argc<3){
31: fprintf(stderr, "Использование setflags: [0][I][A][S][N]"
32: "<filenames>n");
33: return 1;
34: }
35:
36: /* каждая буква представляет флаг; установить
37: флаг, которые указаны */
38: if (strchr(argv[1], 'I') ) flags |= EXT3_IMMUTABLE_FL;
39: if (strchr(argv[1], 'A') ) flags |= EXT3_APPEND_FL;
40: if (strchr(argv[1], 'S') ) flags |= EXT3_SYNC_FL;
41: if (strchr(argv[1], 'N') ) flags |= EXT3_NODUMP_FL;
42:
43: /* пройти по всем именам в argv[] */
44: while (*(++filename)) {
45: /* В отличие от нормальных атрибутов, атрибута ext3 можно опрашивать,
46: только если есть файловый дескриптор (имя файла не годится).
47: Для выполнения запроса атрибутов ext3 нам не нужен доступ на запись,
48: поэтому O_RDONLY подойдет. */
49: fd = open(*filename, O_RDONLY);
50: if (fd < 0) {
51: fprintf(stderr, "невозможно открыть %s:%sn", *filename,
52: strerror(errno));
53: return 1;
54: }
55:
56: /* Установить атрибуты в соответствии с переданными
57: флагами. */
58: if (ioctl(fd, EXT3_IOC_SETFLAGS, &flags)) {
59: fprintf(stderr, "Сбой ioctl в %s:%sn", *filename,
60: strerror(errno));
61: return 1;
62: }
63: close(fd);
64: }
65:
66: return 0;
67: }
11.4. Манипулирование содержимым каталогов
Вспомните, что компоненты каталогов (имена файлов) — это ни что иное, как указатели на дисковые информационные узлы (on-disk inodes); почти вся важная информация, касающаяся файла, хранится в его inode. Вызов open() позволяет процессу создавать компоненты каталогов, которые являются обычными файлами, но для создания файлов других типов и для манипулирования компонентами каталогов могут понадобиться другие функции. Функции, которые позволяют создавать, удалять и выполнять поиск каталогов, описаны в главе 14; файлы сокетов — в главе 17. В настоящем разделе раскрываются символические ссылки, файлы устройств и FIFO.
11.4.1. Создание входных точек устройств и именованных каналов
Процессы создают файлы устройств и именованных каналов в файловой системе с помощью вызова mknod().
#include <fcntl.h>
#include <unistd.h>
int mknod(const char *pathname, mode_t mode, dev_t dev);
pathname — это имя файла, который нужно создать, mode — это и режим доступа (который модифицируется текущим umask), и тип нового файла (S_IFIFO, S_IFBLK, S_IFCHR). Последний параметр, dev, содержит старший (major) и младший (minor) номера создаваемого устройства. Тип устройства (символьное или блочное) и старший номер устройства сообщают ядру, какой драйвер устройств отвечает за операции с этим файлом устройства. Младший номер используется внутри драйвером устройства, чтобы различать отдельные устройства среди многих, которыми он управляет. Только пользователю root разрешено создавать файлы устройств; именованные же каналы могут создавать все пользователи.
Заголовочный файл <sys/sysmacros.h> представляет три макроса для манипулирования значениями типа dev_t. Макрос makedev() принимает старшие номера в первом аргументе, младшие — во втором и возвращает значение dev_t, ожидаемое mknod(). Макросы major() и minor() принимают значение типа dev_t в качестве единственного аргумента и возвращают, соответственно, старший и младший номер устройства.
Программа mknod, доступная в Linux, предоставляет пользовательский интерфейс к системному вызову mknod() (подробности см. в man 1 mknod). Ниже приведена упрощенная реализация mknod для иллюстрации системного вызова mknod(). Следует отметить, что программа создает файл с режимом доступа 0666 (предоставляя право на чтение и запись всем пользователям) и зависит от системной установки umask процесса для получения прав доступа.
1: /* mknod.с */
2:
3: /* Создать устройство или именованный канал, указанный в командной строке.
4: См. подробности о параметрах командной строки
5: на man-странице mknod(1). */
6:
7: #include <errno.h>
8: #include <stdio.h>
9: #include <stdlib.h>
10: #include <string.h>
11: #include <sys/stat.h>
12: #include <sys/sysmacros.h>
13: #include <unistd.h>
14:
15: void usage(void) {
16: fprintf (stderr, "использование: mknod <путь> [b | с | u | p]"
17: "<старший> <младший>n");
18: exit(1);
19: }
20:
21: int main(int argc, const char **argv) {
22: int major = 0, minor = 0;
23: const char *path;
24: int mode = 0666;
25: char *end;
26: int args;
27:
28: /* Всегда необходимы, как минимум, тип создаваемого inode
29: и путь к нему. */
30: if (argc < 3) usage();
31:
32: path = argv[1];
33:
34: /* второй аргумент указывает тип создаваемого узла */
35: if (!strcmp(argv[2], "b")) {
36: mode | = S_IFBLK;
37: args = 5;
38: } else if (!strcmp(argv[2] , "с") || !strcmp(argv[2], "u")) {
39: mode |= S_IFCHR;
40: args = 5;
41: } else if(!strcmp(argv[2], "p")) {
42: mode |= S_IFIFO;
43: args = 3;
44: } else {
45: fprintf(stderr, "неизвестный тип узла %sn", argv[2]);
46: return 1;
47: }
48:
49: /* args сообщает, сколько аргументов ожидается, поскольку нам нужно
50: больше информации при создания устройств, чем именованных каналов*/
51: if (argc != args) usage();
52:
53: if (args == 5) {
54: /* получить старший и младший номера файла устройств,
55: который нужно создать */
56: major = strtol(argv[3], &end, 0);
57: if (*end) {
58: fprintf(stderr,"неверный старший номер %sn", argv[3]);
59: return 1;
60: }
61:
62: minor = strtol(argv[4], &end, 0);
63: if (*end) {
64: fprintf(stderr, "неверный младший номер %sn", argv[4]);
65: return 1;
66: }
67: }
68:
69: /* если создается именованный канал, то финальный параметр
70: игнорируется */
71: if (mknod(path, mode, makedev(major, minor))) {
72: fprintf(stderr, "вызов mknod не удался : %sn", strerror(errno));