Содержание | Части 1-5 | Части 7-8 | Части 9-11 |
Часть 7. Shell: пользовательская оболочка ОС
Предисловие соавтора
Эта часть написана в соавторстве с А.Хапугиным (Hady), реализовавшим ныне здравствующую пользовательскую оболочку, а также интерпретатор командныхх файлов mshell.
Cоавтор
Пользовательская оболочка системы shell - основнoe средство общения с операционной системой. С помощью shell можно изменить обстановку работы как себе, так и окружающим, запустить или прекратить задачу, а также узнать кое-что о состоянии ОС.
Для работы с пользовательской оболочкой достаточно этого описания. Но если читатель хочет продвинуться дальше, понять смысл средств и ограничений shell, мы посоветуем ему ознакомиться с комментариями к библиотекам Shell и exeCut.
Глава 7.1. Окружение и его параметры
Не имея достаточно средств и будучи отфутболенным различными бюрократами, она у меня пока не полностью автоматизирована. Вопросы задаются устным образом, и я их печатаю и ввожу к ей внутрь, довожу, так сказать, до ейного сведения. Отвечание ейное, опять же через неполную автоматизацию, печатаю снова я.
А. и Б. Стругацкие. Сказка о Тройке
7.1.1. Приглашение к вводу команды
Большую часть времени, занимаемого утилитой у компьютера, она тратит на ввод команд с клавиатуры и попытку их исполнить. Выдавая на экран строчку-приглашение, утилита приглашает пользователя ввести строку-команду.
Стандартное приглашение состоит из текущего времени и текущей директории и выглядит приблизительно так:
12:35 dir $
Если оно не подходит вам, его легко поменять, набрав PROMPT="приятная_глазу_строка". Теперь в качестве приглашениея будет выдаваться
приятная_глазу_строка
В нее могут быть включены последовательности из двух символов %/ и %t, которые перед выводом строки-приглашения на экран заменяются на имя текущей директории и на текущее время соответственно.
Например, было указано приглашение
PROMPT="Время: %t Директория: %/ >> "
Eсли сейчас 12 часов 35 минут, а текущая директория - "/usr/John/games", то строка-приглашение будет выглядеть теперь следующим образом:
Время: 12:35 директория: games >>
Впрочем, такое длинное приглашения не очень удобно, поэтому будем считать, что установлено приглашение "]", и именно им будем предварять изображаемые далее командные строки.
Конец 7.1.1.
Установив новое приглашение, вы, сами того не зная, изменили значение одного из параметров своего окружения, а именно параметра PROMPT.
Каждая задача запускается в некотором окружении, содержащем необходимую (по крайней мере, не вредную) для ее исполнения информацию. Окружение задачи (а shell - тоже задача) состоит из набора ПАРАМЕТРОВ, у которых есть имя ("PROMPT") и значение (теперь "]").
Откуда берется окружение вновь запускаемой задачи? Его создает запускающая задача (в нашем случае shell) при запуске. Получает она его простым копированием почти всех (подробности см. в п.7.3.6) параметров своего собственного окружения.
7.1.2. Изменение параметров окружения
С клавиатуры можно задать или изменить (если уже задано) значение любого параметра, набрав строку "ИМЯ=тело", и в окружении вашей shell параметр ИМЯ примет значение "тело".
Обратите внимание: если "тело" не содержит пробелов, то брать его в кавычки необязательно.
Удалить параметр из окружения еще проще: достаточно сказать "ИМЯ=", и параметр с именем "ИМЯ" исчезнет.
7.1.3. Изменение параметров чужого окружения
Можно сменить окружение не только вашей shell, но и любой другой задачи. Для этого перед именем параметра надо поставить номер задачи, у которой требуется сменить параметр, и отделить этот номер от имени точкой, например:
]69.PROMPT="ex.shell>>"
Вместо номера годится и имя уже существующего параметра, если его значение - запись какого-нибудь целого числа, как, например, у параметров FATHER, TASK или BASE. Для этого нужно поставить имя этого параметра вместо номера и предпослать ему символ "$, например:
]$FATHER.INFO="кафолик недорезанный"
Такая возможность дает, естественно, почву для мелкого хулиганства, но есть у нее и серьезные применения, о которых - в главе про командные файлы.
Следует при этом помнить, что если номер указан неправильно, или задачи с таким номером не существует, то вся конструкция "НОМЕР.ИМЯ" будет проинтерпретирована как имя нового параметра.
7.1.4. О приватных параметрах
Есть еще одна маленькая тонкость: если перед именем (или номером задачи и именем, если речь идет о чужом окружении) параметра поставить ".", то эта точка не войдет в имя получившегося параметра, а станет признаком приватности параметра: такой параметр не будет копироваться в окружения задач, запущенных вашей shell. А если вам все-таки хочется начать имя параметра с точки, то поставьте перед ней символ "\".
7.1.5. Имя параметра вместо его значения
Если требуется передать значение параметра в качестве аргумента какой-либо команде, вместо значения можно написать имя параметра, предварив его символом "$".
При выполнении любых действий shell заменяет в строке аргументов действия все комбинации вида "$ИМЯ" на значения параметров с именем "ИМЯ", если они есть в окружении, и только потом исполняет действие.
Глава 7.2. Команды shell
Кроме параметра "PROMPT", в окружении вашей shell может быть (и обычно бывает) много других параметров. Некоторые из них заметным образом влияют на поведение shell, а некоторые отражают ее состояние. Значения основной части параметров демонстрирует команда "set".
7.2.1. Как узнать текущие значения параметров (set)
По команде "set" shell печатает на экране состояния тех параметров, которые считает существенными. Команда
]set
вызовет появление на экране следующей информации:
USER "Iam"
HOME "/usr/Iam"
NAME "shell"
TASK "155"
FATHER "66"
BASE "155"
SHELL "shell"
STK "8"
CEMETRY "1"
CD "/usr/Iam/my_dir"
BIN ". /bin /usr/bin"
SYM ". /sym /usr/sym"
ETC ". /etc /usr/etc"
REF ". /ref /usr/ref"
TTY "/dev/tty2"
KEY "/dev/key2"
PROMPT "%t %/ $ "
INSERT "1"
ECHO "0"
BELL "1"
Еще раз заметим, что это не все параметры вашего окружения, наверняка есть еще и другие. Можно узнать и их значения. Наберите
]set S*
SYM ". /sym /usr/sym"
SCR "/dev/bmap"
STK "4"
SHELL "mshell"
Можно заметить, что кроме того, что напечатаны параметры, имена которых начинаются на "S", появился еще один параметр с именем "SCR".
Аргумент команды set "S*" использован как регулярный образец, и команда напечатала все параметры, чьи имена сопоставились с этим образцом. Если учесть, что с образцом "*" сопоставляются все строки, то ясно, что посмотреть совсем все параметры можно, набрав
]set *
FATHER "66"
BASE "48"
TASK "48"
ARGS ">t"
NAME "t"
HOME "/usr/hady"
USER "hady"
REF ". /ref /usr/ref"
SYM ". /sym /usr/sym"
PROMPT "%t %/ $ "
BELL "1"
LP "/dev/lp0"
CPD "/dev/mou0"
MSG "/dev/LATIN"
SCR "/dev/bmap"
ETC ". /etc /usr/etc"
BIN ". /bin /usr/bin"
STK "4"
ECHO "0"
SHELL "mshell"
KEY "/dev/key0"
TTY "/dev/tty0"
CD "/usr/hady/sh/doc"
Конец 7.2.1.
Ни команда "set", ни модификации окружения не приводят к запуску каких-либо задач, эти команды - внутреннее дело самой shell. Есть еще несколько команд, чье исполнение полностью находится в компетенции shell. Остановимся на них подробнее.
7.2.2. Информация о задачах (ps)
По команде "ps" shell выдает на экран некоторую информацию о запущенных в настоящий момент задачах, например:
] ps
0153 run ex shell.doc
0066 run shell
Первая колонка - номера задач. Номер, в отличие от имени задачи, уникален, и потому более удобен для работы с задачей (прекращение, удаление, история завершения).
Вторая колонка - состояние задачи. Кроме "run" (запущена) задача может находиться в состояниях "stop" (остановлена), "load" (загружена) или еще каком-нибудь.
Третья колонка - имена задач.
Четвертая - некая дополнительная информация. В приведенном примере видно, что редактор "ex" сейчас занят файлом "shell.doc", содержимое которого у вас перед глазами. Заметим, что эта дополнительная информация - всего лишь строчка окружения задач с именем "INFO". Попробуйте набрать
] .INFO="кафолик недорезанный"
а потом спросить "ps":
] ps
и вы убедитесь в том, что программы тоже могут грубить:
0153 run ex shell.doc
0066 run shell кафолик недорезанный
У команды "ps" могут быть модификаторы "-tty", "-usr", "-mem", "-l", "-all".
7.2.2.1. Модификатор usr
Наберите
]ps -usr
0153 run Iam soft ex shell.doc
0066 run Iam soft shell
Появились две новые колонки: имена пользователя и его группы.
7.2.2.2. Модификатор tty
]ps -tty
Модификатор "tty" добавит колонку с информацией о терминале, с которого запущена задача.
7.2.2.3. Модификатор mem
]ps -mem
Модификатор mem добавит информацию о памяти, занятой задачей.
7.2.2.4. Модификатор l
Модификатор "l" заменяет все три перечисленных модификатора:
] ps -l
0153 run Iam soft 62K+0624 /dev/tty2 ex shell.doc
0066 run Iam soft 22K+0316 /dev/tty2 shell
7.2.2.5. Модификатор all
Обратите внимание: все показанные задачи запущены одним пользователем - вами, как будто других на машине нет. Может, это и так, но не всегда. Просто вам показывают НЕ ВСЕ задачи, а только запущенные с вашим пользовательским кодом. Чтобы увидеть ВСЕ задачи, используйте модификатор "all":
] ps -all
...TASKS...
0153 run ex shell.doc
0066 run shell
0015 + run login
0012 + run DK6fd4110
0010 + run TT6FCT
0009 + run SIq6
0008 + run CCDqMOUSE
0007 + run DK6qSCSI
0006 + run tmspo
0005 + run LEXICON
0002 + run TT6FCT
0001 + run DK6dq615
Задач стало больше! Теперь это действительно все задачи. Модификатор "-all" можно применять в комбинации с другими для получения расширенной информации. Например,
] ps -all -mem
...TASKS...
0153 run 62K+0624 ex shell.doc
0066 run 22K+0316 shell
0015 + run 13K+0976 login
0012 + run 7K+0476 DK6fd4110
0010 + run 9K+0936 TT6FCT
0009 + run 9K+0936 SIq6
0008 + run 11K+0496 CCDqMOUSE
0007 + run 7K+0936 DK6qSCSI
0006 + run 13K+0976 tmspo
0005 + run 15K+0352 LEXICON
0002 + run 8K+0920 TT6FCT
0001 + run 5K+0132 DK6dq615
ясно показывает, что больше всех памяти отъел редактор с файлом "shell.doc", а что поделаешь?
В конце строки можно указать номера задач, информацию о которых вы хотите получить. Если модификатор all отсутствует, вы получите информацию только об указанных задачах.
Символ "+" сразу после номера задачи обозначает, что эта задача сейчас находится в режиме привилегированного доступа. Этот режим позволяет иногда обойти ограничения, связанные с защитой файлов. Перейти в него можно с помощью команды "su".
7.2.3. Привилегированный доступ (su и us)
Команда "su" используется для переведения вашего shell'а в режим привилегированного доступа. Чтобы добраться до защищенных от вас файлов, наберите "su":
] su
Вот незадача! Требуют пароль:
password:
Если вы знаете его - введите, и тогда вы, работая под своим именем, сможете попользоваться привилегированным доступом. Если не знаете - не сможете. А если вы администратор системы, никто не помешает вам сделать в своем пользовательском коде специальную пометку, которая избавит вас от необходимости знать и набирать пароль: у вас его даже не спросят.
Поработав в привилегированном режиме, не забудьте от него отказаться - так спокойнее. Это делается командой "us".
7.2.4. Как гулять по директориям (cd)
Через несколько поколений картофелю наскучил оседлый образ жизни, он самостоятельно выкопался и перешел к кочевому состоянию.
С.Лем. Звездные дневники Ийона Тихого
Иногда возникает желание (или даже необходимость) сменить текущую директорию. Сделать это просто:
my_dir] cd my_another_dir
my_another_dir]
Этот номер пройдет гладко, если на директории my_dir действительно имеется директория my_another_dir. Если ее нет, то вам намекнут на ошибку:
my_dir] cd my_another_dir
#no such entry: change_dir("my_another_dir")
С помощью этой команды можно узнать и имя текущей директории. Достаточно набрать просто "cd":
my_dir] cd
#current directory: /usr/Iam/my_dir
Здесь нелишне упомянуть, что имя текущей директории хранится в окружении под именем "CD" (этот параметр показывает команда "set"). Более того: команда "cd any_name" полностью эквивалентна команде "CD=any_name".
7.2.5. Показ распределения памяти (mem)
Команда "mem" демонстрирует распределение оперативной памяти компьютера:
] mem
...MEMORY TOTAL...
available 1024K+0000
core 216K+0472
free 356K+0068
busy 451K+0484
Строчка "available" обозначает полный объем памяти, доступной системе, "core" - объем памяти, занятой системой, "free" - объем свободной памяти, а "busy" - объем памяти, занятой всеми задачами.
7.2.6. История задачи (his)
Откинув уши на плечи, он рассказал мне историю своих соотечественников.
С.Лем. Звездные дневники Ийона Тихого
Команда "his" печатает на экране историю последней неудачно закончившейся задачи. Если таковых еще не было, на экран выдается
#no history
С помощью команды his можно узнать историю любой задачи, еще находящейся в памяти, даже если она не завершена. Для этого достаточно указать этой команде номер нужной задачи.
Замечание. | Параметр окружения HISTORY хранит историю последней неудачно завершившейся задачи или строчку "#no history", если задачи не было. При вызове без указания номера задачи команда просто распечатывает содержимое параметра. |
7.2.7. Задержка на несколько секунд (delay)
Команда
] delay N
, где N - целое число, приведет к тому, что shell просто ничего не делает N секунд. Такое действие может показаться странным, но оно бывает полезным в некоторых "хитрых" случаях администратору системы.
Администратору системы будут полезны и следующие две команды: "mount" и "unmount".
7.2.8. Монтирование дисков (mount,unmount)
Команда "mount" позволяет изменить файловое дерево методом монтирования нового диска вместо какой-нибудь директории. Например,
] mount /mnt /dev/fd0
приводит к тому, что если устройство /dev/fd0 существует, и если оно - диск с нормальной файловой системой, а также существует директория /mnt (и если она доступна пользователю), то после исполнения вышеозначенного действия вместо директории /mnt в файловом дереве будет корневая директория носителя, находящегося на устройстве /dev/fd0.
Правда, при таком способе монтирования на этот диск записать ничего не удастся: он защищен системой от записи. При желании писать на него после монтирования нужно добавить модификатор "-ro":
] mount /mnt /dev/fd0 -ro
Демонтировать диск и получить, таким образом, доступ к содержимому директории /mnt можно командой "unmount":
] unmount /mnt
Замечание. | Вообще-то в системе есть специальная утилита mou для монтирования и демонтирования дисков. Программисты обычно пользуются ею, потому что она удобней и много чего умеет. |
7.2.9. Управление задачами (stop, kill, wait)
- ... И я, старший здесь, нарушая законы и правила, первый говорю: смерть!
Рядовые члены Тройки вздрогнули и разом заговорили.
- Которого? - с готовностью спросил Хлебовводов, понявший, по-видимому, только последнее слово.
А. и Б. Стругацкие. Сказка о Тройке
Команды управления могут быть названы таковыми с некоторой натяжкой, поскольку все управление сводится к прекращению (stop), удалению (kill) или ожиданию окончания (wait) задачи. Команды запускаются одинаково:
] wait <номера_задач>
дождаться окончания задач с указанными номерами. Это ожидание, если оно стало слишком тягостным, может быть в большинстве случаев прервано с клавиатуры нажатием CTRL_C.
] stop <номера_задач>
- прекратить исполнение задач с указанными номерами, не выгружая их из памяти. После выполнения этой команды можно посмотреть историю задачи.
] kill <номера_задач>
- прекратить исполнение задач с указанными номерами и выгрузить их из памяти. Если задача уже была остановлена, то команда только выгружает ее из памяти. После этого от задачи не остается уже ничего, даже ее трупа.
Номера задач в строке аргументов перебираются до тех пор, пока не встретится конец строки или неправильный номер.
Заметим, что отсутствующую задачу можно считать нормально законченной, следовательно, все три команды не считают ее отсутствие ошибкой.
7.2.10. Завершение работы с shell
Команда bye заканчивает работу с пользовательской оболочкой. После набора команды shell исчезает.
Конец 7.2.10.
Итак, мы познакомились с окружением shell, его параметрами, которые можно изменять как явно, так и с помощью команд. Перечислим еще раз все команды shell:
- set - показ текущих значений параметров;
- cd - смена текущей директории;
- ps - показ информации о задачах;
- mount, unmount - монтирование и демонтирование носителя;
- his - показ истории задачи;
- mem - показ распределения памяти;
- kill - удаление задачи;
- wait - ожидание завершения задачи;
- stop - остановка исполнения задачи;
- delay - задержка на несколько секунд;
- su,us - переход к привилегированному доступу и обратно;
- bye - завершение работы с shell.
Глава 7.3. Запуск задач
Если введенная строка не является командой shell, то shell интерпретирует ее как имя запускаемой задачи и пытается запустить эту задачу.
7.3.1. Простой случай
Простейший способ запустить задачу - набрать ее имя:
] ls
запустится задача "ls", которая показывает имена файлов, расположенных на текущей директории.
Если дополнить имя задачи расширением ".cod", то произойдет то же самое. При этом нужно помнить, что поиск кода задачи будет происходить сначала по памяти - по прямым предкам новой задачи, а затем по диску - по директориям, описанным строкой "BIN" окружения пользователя (читайте об этом в разделе о задачах в ОС Excelsior). Если код не найден, то shell сообщит об этом.
Можно указать полное имя кодофайла. Например,
] /bin/ls
заставит shell временно поменять текущую директорию на /bin, загрузить задачу, а затем вернуться на прежнюю директорию и запустить загруженную задачу.
Часто возникает необходимость передать задачам какие-нибудь аргументы. Аргументы вводятся после имени задачи. На них распространяется Замечание из п.1.10. Например:
]ls $HOME
печатает имена файлов собственной директории пользователя.
]echo $HISTORY
выдает значение параметра HISTORY, если он есть в окружении; иначе строчку $HISTORY.
7.3.2. Запуск независимых задач
По способу исполнения задачи в ОС Excelsior делятся на независимые (открепленные) и зависимые. Завершения независимой задачи никто не ждет; она исполняется параллельно с исполнением других задач. Завершения зависимой задачи shell ожидает и освобождает по завершении занимаемые ею ресурсы: закрывает открытые задачей файлы, освобождает память из-под задачи.
Для того, чтобы задача запустилась как независимая, поместите символ "&" в конец строки аргументов:
]<задача> <аргументы> &
Например:
]ls -1 >listing &
позволит записать в файл listing список всех файлов текущей директории в одну колонку, а программист тем временем может заниматься редактированием какого-нибудь текста.
Символ "&" из строки аргументов изымается и задаче не передается. При необходимости передать именно его в качестве последнего аргумента предварите его символом "\".
7.3.3. После того, как задача запущена
7.3.3.1. Прекращение зависимой задачи
После запуска зависимой (неоткрепленной) задачи shell дожидается ее окончания, и только после этого принимает новые команды.
При желании почти всегда задачу можно прервать нажатием CTRL_C на клавиатуре, или открепить нажатием CTRL_X (случаи, когда это невозможно, будут описаны позднее).
7.3.3.2. Параметр CHAIN
При нормальном окончании зависимой задачи перед ее удалением из памяти shell проверяет в ее окружении наличие параметра "CHAIN", и если он есть - интерпретирует его значение как следующую команду.
Замечание. | Среди значений параметра "CHAIN" не исполняются команды, описанные в п.п.1.2.-1.8., а также команда "bye". (Вдумчивый читатель, прочитавший уже описания библиотек Shell и exeCut, наверняка понял, откуда это ограничение, и теперь имеет повод слегка повеселиться над нами. Что ж, нет в мире совершенства ...) |
7.3.3.3. О трупах задач зависимых и независимых
Если зависимая задача завершилась нормально, ее "труп" (коды, процедурный стек, глобалы, созданные задачей структуры) удаляется системой из памяти автоматически.
Если же она завершилась аварийно, ее труп удаляется из памяти только тогда, когда в окружении shell нет параметра с именем "CEMETRY", или его значение - ноль. В противном случае несчастные останки остаются в памяти до явного удаления (например, командой "kill").
Остаются в памяти также и трупы аварийно законченных независимых задач до явного их уничтожения командой kill.
Кстати, пока труп не удален из памяти, можно ознакомиться с историей болезни с помощью команды his (программисты обычно пользуются утилитой hi, которая предоставляет информацию в более удобной форме, см. справочник по утилитам).
Теперь вы, пожалуй, знаете, как запустить задачу, но некоторые тонкости этого действия заслуживают более подробного разговора.
7.3.4. Управление деревом задач
Замечание. | При возникновении неясностей, касающихся организации дерева задач, советуем обратиться к разделу, посвященному задачам в ОС Excelsior. |
Любая задача создается на базе другой задачи. Термин "создание на базе" здесь обозначает, что новая задача становится потомком другой, на чьей базе она создана, а задача-база, в свою очередь, - предком новой задачи.
Что означает отношение потомок-предок? Это означает, что кодофайлы для новой задачи сначала будут разыскиваться по ее прямым предкам, начиная от задачи-базы, а также задача может разделять глобалы какого-либо модуля только с одним из своих предков. И еще: при любом окончании задачи все ее потомки бессердечно уничтожаются.
Номер задачи-базы shell извлекает из параметра BASE своего окружения. Отсутствие такого параметра приводит к невозможности запустить какую-либо задачу.
Замечание. | По соглашениям ОС Excelsior iV, все задачи начинают нумероваться с единицы (1). Если значение параметра BASE равно 0, это означает, что в качестве базы задачи используется ядро ОС. Это может быть полезным, например, при запуске драйверов. |
Ясно, что запускающая задача (в нашем случае shell) в общем случае не имеет к базе никакого отношения - только то, что в окружении запускающей задачи указан номер задачи-базы для всех запускаемых задач.
7.3.5. Управление поиском кодофайлов
Перед именем задачи в строке может находиться некая информация, заключенная в фигурные скобки "{}". В частности, в таких скобках можно указать способы поиска кодофайлов.
Так, комбинация "-имя_модуля" обозначает, что модуль "имя_модуля" нужно обязательно загрузить с диска, даже если он был найден у одного из предков; комбинация "+имя_модуля" обозначает, что модуль "имя_модуля" необходимо найти у одного из предков и не копировать его глобалы (считать его уникальным); комбинация "=имя_модуля имя_файла" означает, что модуль "имя_модуля" нужно взять с диска, причем искать его в файле "имя_файла".
Например:
]{+myEditor} turbo2x
запустит в редакторе фильтр turbo2x, который является Модула-компилятором. Так простой текстовый редактор превращается в турбину.
Необходимо учесть, что здесь действует Замечание из п.7.2.10 о копировании комбинаций типа "$NAME".
Строчки "+имя_модуля", "-имя_модуля", "=имя_модуля имя_файла" можно занести в параметр окружения "ALIAS". После этого ВСЕ запуски задач будут осуществляться с указанными изменениями.
7.3.6. Управление окружением запускаемых задач
Каждая задача запускается с некоторым окружением. Окружение задачи получается простым копированием всех параметров окружения запускающей задачи (в нашем случае shell). Надо учесть, что параметры, помеченные как приватные, не копируются.
При этом над окружением новой задачи производятся следующие действия:
- удаляется параметр "CHAIN";
- создаются параметры "TASK", "FATHER", "NAME";
- если отсутствует, то создается параметр "BASE", со значением, равным "TASK".
И уже потом из части строки между скобками "{}", если она есть, выбираются все комбинации вида "NAME=string" и используются как указания к модификации окружения новой задачи.
Замечание. | Такие комбинации выбираются, начиная с символа "{", до первой неподходящей комбинации; вся остальная строка до "}" считается изменением поиска кодофайлов, о котором говорилось в п.7.3.5. |
Таким образом, запуск ls ../
эквивалентен { CD=.. } ls
Глава 7.4. Запуск командных файлов
Если попытка запустить задачу провалилась из-за отсутствия кодофайла (файла с расширением .cod), но в одной из директорий, перечисленных в параметре "ETC" окружения, обнаружился файл с именем "имя_задачи.@" (или "имя_задачи.sh"), то shell решит, что нужно запустить командный файл с этим именем. При желании запустить именно командный файл, даже если существует кодофайл с таким именем, укажите имя с требуемым расширением.
Иерархия при запуске задачи без явно указанного расширения будет такая: shell сначала разыскивает файл с расширением ".@"; не найдя, ищет файл с расширителем ".cod"; если же и такого не находит, пытается найти файл с расширителем ".sh".
Имеются две возможности в зависимости от того, с каким командным файлом мы имеем дело - ".sh" или ".@".
7.4.1. Запуск со специальным интерпретатором и без него
Если имя командного файла имеет расширение ".sh", то происходит следующее.
Для запуска командного файла shell ищет в своем окружении параметр с именем "SHELL", считает его содержимое именем установленного интерпретатора командных файлов и запускает задачу с таким именем, поправив для нее строку параметров: в ее начало будет вписано имя командного файла с префиксом "<". Например, если в вашем окружении "SHELL=mshell" и вы набрали строку
] { CD=/usr/bin } /usr/games/comp.@ poker xonix
, то это эквивалентно запуску
] { CD=/usr/bin } mshell </usr/games/comp.@ poker xonix
Отметим, что прелюдия в скобках "{}" относится к задаче "mshell".
Если параметр "SHELL" в окружении отсутствует, то командный файл с расширением ".sh" не может быть запущен.
Из всего сказанного можно сделать два тревожных вывода: во-первых, командный файл интерпретируется ОТДЕЛЬНОЙ ЗАДАЧЕЙ, во-вторых - он интерпретируются не shell, а чем-то другим.
Первое замечание очень важно, и мы его подробно обсудим ниже (7.4.3.), а по поводу второго скажем, что shell тоже умеет интерпретировать командные файлы, и имя shell можно смело указывать в строчке окружения SHELL.
Замечание. | Более того, командный файл может быть запущен и проинтерпретирован именно тем экземпляром задачи shell, "под которым" вы работаете. Для этого командный файл должен иметь расширение ".@". |
7.4.2. Как shell интерпретирует командный файл
Командный файл полагается текстовым файлом с разделителем между строками ASCII.NL (код 036c). Строки не должны быть длиннее 255 символов (в противном случае выдается сообщение об ошибке). Если в прочитанной строке первый символ, отличный от пробела, равен "%", то строка считается комментарием и не исполняется.
В строках, прочитанных из файла, комбинации вида "$1","$2".."$9" заменяются на соответствующие аргументы командного файла с номерами соответственно 1,2..9 (в приведенном выше примере $1 обозначает "poker", $2 обозначает "xonix", а остальные обозначают пустую строку). Комбинации "\$" заменяются на "$", с отменой специального значения "$", а комбинации "\\" заменяются на "\". Результирующая (после всех подстановок) строка тоже не должна быть длиннее 255 символов.
Если в окружении shell'а-интерпретатора параметр "ECHO" есть и не равен "0", то обработанная строка будет напечатана на экране терминала. В тех же случаях печатаются на экране строки-комментарии.
После всего этого строка будет исполнена, как будто ее ввели с клавиатуры, кроме команды "bye".
Учитывая, что утилита shell вполне подходит для интерпретации командных файлов, имеет смысл именно ее имя хранить в окружении под именем "SHELL" (спросите "set", наверняка в вашем окружении так оно и есть).
7.4.3. Кто исполняет командный файл?
Тот факт, что командный файл исполняется отдельной задачей, приводит к некоторым особенностям, которые необходимо учитывать при его написании.
Первая особенность: у командного файла есть СВОЙ экземпляр окружения. Это значит, что значения параметров окружения командного файла могут отличаться от параметров вашей shell, и что модификации окружения по умолчанию относятся к окружению именно командного файла, а не shell.
Поясним это на примере. Набранные с клавиатуры команды
]echo $TASK
].INFO="кафолик недорезанный"
приведут к тому, что отпечатается номер вашей shell, и в именно в окружении shell появится ругачая строчка.
Эти же команды, помещенные в командный файл t.sh, после исполнения последнего приведут к тому, что напечатается другой номер (а именно - номер интерпретирующей shell), а окружение вашей shell не изменится совсем (изменится окружение shell-интерпретатора, которое пропадет после завершения его работы).
Таким образом, чтобы с помощью командного файла изменить параметры именно вашего окружения, нужно предварить их имена номером вашей shell. Если вы хотите, чтобы командный файл t.sh исполнил то, что от него ожидается, исправьте его следующим образом:
echo $FATHER
.$FATHER.INFO="кафолик недорезанный"
Вторая особенность: при исполнении командного файла клавиатурные прерывания (CTRL_X, CTRL_C) действуют не на ту задачу, которая запущена из командного файла, а на весь командный файл в целом, то есть CTRL_C прерывает, а CTRL_X открепляет тот shell, который интерпретирует командный файл.
Глава 7.5. Когда CTRL_C не действует
Включив тормоза, я вдруг обнаружил, что они не действуют и что корабль камнем падает на планету. Выглянув в люк, я увидел, что тормозов вообще нет.
С.Лем. Звездные дневники Ийона Тихого
Как уже говорилось, по соглашениям ОС Excelsior существуют два символа, на которые установлена специфическая реакция: CTRL_X и CTRL_C. Первый обозначает открепление задачи, второй - ее прекращение. Эти символы действуют на все запущенные вашим shell задачи. Поскольку ваша shell запущена не ей самой, она не прекращается по нажатии этих клавиш.
Если вы запустили командный файл, то нажатием "CTRL_U" на своей клавиатуре вы прервете исполнение ВСЕГО командного файла, а не только той команды, которая исполнялась в момент нажатия.
Правда, существует исключительный случай, когда эти символы не действуют. Система предоставляет возможность задаче иметь собственный обработчик символов, посланных с клавиатуры. Перехватив у shell посланный CTRL_C, задача, имеющая такой обработчик, может отреагировать на него так, как считает нужным - например, никак не отреагировать.
Глава 7.6. Общее описание утилиты shell
- Высочайшие достижения нейтронной мегалоплазмы! - провозгласил он. - Ротор поля наподобие дивергенции градуирует себя вдоль спина и там, внутре, обращает материю вопроса в спиритуальные электрические вихри, из коих и возникает синекдоха отвечания...
А. и Б. Стругацкие. Сказка о Тройке
Shell - универсальная утилита и имеет несколько функций, которые зависят от ключа, с которым запускается утилита.
7.6.1. Раскрутка системы после загрузки
Способ запуска:
shell root=<имя_директории>
используется в файле конфигурации системы при ее раскрутке.
При раскрутке системы выполняются следующие действия:
- текущая директория устанавливается на указанную директорию;
- на текущей директории ищется командный файл с именем "profile.@" и исполняется;
- shell заканчивается.
7.6.2. Ведение диалога с пользователем
Запуск:
shell -home <имя_директории_пользователя>
осуществляется утилитой входа в систему login или администратором непосредственно.
При этом выполняются следующие действия:
- текущая директория устанавливается на указанную директорию;
- исполняется командный файл с именем $TTY_up.@;
- исполняется командный файл "profile.@" с текущей директории;
- в окружение заносятся параметр HOME с именем указанной директории и параметр USER с именем пользователя;
- начинается диалог с пользователем.
7.6.3. Интерпретация командных файлов
shell "<"имя_командного_файла { аргументы }
Может быть запущена пользователем для исполнения командного файла.
По пути, указанному в ETC, ищется файл с указанным именем, интерпретируется как командный файл, после чего утилита завершается.
7.6.4. Запуск без аргументов
shell
Ведет диалог, который заканчивается либо по команде bye, либо по нажатии клавиши Esc.
Глава 7.7. Приложение: перечень параметров окружения
shell использует следующие параметры окружения:
SHELL | имя утилиты, которая вызывается при обнаружении командного файла. Параметр копируется обычным образом; его отсутствие приводит к невозможности исполнить командный файл. |
STK | размер стека для запускаемых задач в килобайтах. Копируется обычным образом. Если в окружении отсутсвует, то размер считается равным 4. |
ALIAS | строка управления поиском модулей. |
BIN | строка имен директорий, на которых производится поиск кодофайлов. |
ETC | строка имен директорий, на которых производится поиск командных файлов и файлов данных. |
CD | имя текущей директории. shell поддерживает ее корректность. |
TTY | имя устройства-экрана. Копируется обычным образом. При модификации этого параметра происходит захват специфицированного устройства. |
KEY | имя устройства-клавиатуры. Копируется обычным образом. При модификации этого параметра происходит захват специфицированного устройства. |
HOME | имя собственной директории пользователя. |
TASK | номер задачи "shell". |
BASE | номер задачи, на базе которой запускаются другие задачи. Если параметр отсутствует, то создается при запуске shell со значением "$TASK". Отсутствие приводит к ошибке при запуске задач. |
FATHER | номер задачи-родителя. Для задач, запущенных shell, этот номер берется из параметра BASE запускающего shell'а. |
SON | номер последней запущеной shell'ом задачи. |
NAME | имя задачи. |
USER | имя пользователя. |
CEMETRY | [0/1] - хоронить ли трупы неоткрепленных задач при их аварийном завершении. При отсутствии параметр считается равным 1. |
CHAIN | post-mortem команда. Если в окружении нормально завершенной неоткрепленной задачи будет найдена строка с таким именем, то она будет исполнена. |
PROMPT | формат строчки-приглашения на ввод команды. |
INSERT | включение-выключение режима вставки при редактировании строки. |
BELL | включение-выключение звукового сигнала при редактировании строки. |
BIN | директории, на которых ищутся необходимые кодофайлы. |
ETC | директории, на которых ищутся командные файлы. |
ECHO | включение эхо-режима: показ всех команд перед исполнением. |
Глава 7.8. Приложение: синтаксис команд shell
command ::= shell_command
| change_environment0
| task_control
| mount_unmount
| run_task .
shell_command ::= set | mem | ps | his |
su | us | cd | bye |
home| delay .
su ::= "su" .
us ::= "us" .
set ::= "set" [ pattern ] .
mem ::= "mem" .
bye ::= "bye" .
his ::= "his" [ number ] .
cd ::= "cd" [ new_cd_name ] .
home ::= "home" [ new_home_dir_name ] .
delay ::= "delay" number .
ps ::= "ps" { modifyer } { number } .
modifyer ::= "-mem" | "-tty" | "-usr" | "-l" | "-all" .
change_environment0 ::=
["."] [ task_number "." ] var_name "=" string .
task_control ::= "stop" task_number { task_number }
| "kill" task_number { task_number }
| "wait" task_number { task_number } .
task_number ::= целое беззнаковое число | $name .
run_task ::= [ "{" {change_environment1} {alias} "}" ]
task_name { args } [ "&" ] .
change_environment1 ::= ["."] var_name "=" string .
alias ::= interface|unload|rename .
interface ::= "+" module_name .
unload ::= "-" module_name .
rename ::= "=" module_name file_name .
mount_unmount ::= "mount" directory device ["-ro"]
| "unmount" directory .
string ::= name | '"' { char } '"' | "'" { char } "'" .
Часть 8. Файловая подсистема
Предисловие
Предисловие соавтора
Эта часть целиком написана Д.Кузнецовым (Leo). Я постаралась, насколько это было возможно, сохранить не только всю информацию, но и прелесть своеобразного языка, на котором пишет автор (Leopold-Russian), несколько изменив, по его желанию, только орфографию и синтаксис, а также произведя разбивку повествования на главы в соответствии с общим стилем книги.
Предисловие автора
Перед тем, как приступить к обсуждению основных концепций, положенных в основу ФАЙЛОВОЙ СИСТЕМЫ ОС Excelsior, мы считаем необходимым дать короткие, но точные, простые, но полные определения используемым в описании терминам и словам, употребленным в специальных значениях. Мы приложили колоссальные усилия для составления этого краткого, но емкого глоссария, которым и хотим предварить знакомство читателя с новейшими концепциями, изложенными в последующем описании.
Тем не менее, мы осознаем, что не смотря ни на какие усилия, в текст глоссария, формальный по духу своему, могли, к сожалению, вкрасться неточности и погрешности. Мы будем искренне признательны всем, кто выскажет свои замечания и укажет на необходимость дополнений.
Короткий глоссарий
ФАЙЛ - (м.род)
полезная фитюлька, точное определение коей с ходу дать возможным не представляется.
(Син. FILE).
УСТРОЙСТВО -
(ср.род) эдакая штука, устроенная разработчиками для пущего увеселения
программеров. Его полезно от программера прятать, или, на худой конец,
скрывать, чем и занята СИСТЕМА УПРАВЛЕНИЯ ФАЙЛАМИ (см.).
(син. DEVICE).
СИСТЕМА УПРАВЛЕНИЯ
ФАЙЛАМИ - (ж.род) плод ...героически- бесполезных усилий по... упрятыванию от
программера всех фитюлек первой необходимости в повседневном обиходе.
(Син. FILE SYSTEM, BASIC
INPUT/OUTPUT).
НОСИТЕЛЬ - (м.род) можно носить, если габариты позволяют. Встречаются квадраты плоско-гибкие примерно 5 и 8 дюймов (син. FLOPPY) - удобны в переноске. Огнестрельные (син. WINCHESTER) представители не стреляют, монтаж/демонтаж (син. mount/unmount) осложнен, к переноске в большинстве своем пригодны. Встречаются крупногабаритные монстры... некоторые представители успешно используются для хранения всякой абракадабры (см.).
ИНФОРМАЦИЯ - (ж.род)
абракадабра вроде той, что вы уже прочли(?) и еще прочтете(!)
(Син. INFORMACIJA (~tion?)).
ДИСКОВОД - (дик.род)
носители водит, пока их не носят, иногда 50 оборотов в секунду, ингода 60, а
иногда - 6, а жаль.
(син. [FLOPPY|WINCHESTER|XBZ] DISK
DRIVE).
ТЕРМИНАЛ - (неопр.род) очень похож на ЧБ или ЦВ телевизор, но футбол и новости не всегда, изображение в основном из БУКВ, ЦИФР и КОРЮЧЕК, похоже на ВЕЗЕР РИПОТ и так же не понятно... Ксати, это - устройство...
ВЕЗЕР РИПОТ - прогноз погоды (син. WEATHER REPORT).
СИМВОЛ - КОРЮЧКА, БУКВА или ЦИФРА.
БАЙТ - емкость для корючек объемом 8 БИТ.
БИТ - емкость для "чего или ничего".
КЛАВИАТУРА - (ж.род) а чем же я, по-вашему, пишу?
(син. KEYBOARD = кнцлрские кнпк на дуб.дск).
СПЕЦИАЛЬНОЕ
УСТРОЙСТВО - (ср.род) не ТЕРМИНАЛ,
с е и л н е не КЛАВИАТУРА,
п ц а ь о НЕ дисковод,
иногда бывают на самом
деле (мышки,кошки,кодировщики, шифровальшицы и т.п.) но в основном измышляются
мстительными программерами для запутывания разработчиков устройств, когда предпоследние
все же ткнутся в софтвер.
СУ доверять нельзя
(как и всему Спец.Х.), проверьте сначала как следует, вдруг оно не настоящее, а
только кажется?
(Син. SPECIAL [sometimes and
somewhere - VIRTUAL] DEVICE).
СИСТЕМА - (мн.ч.) совокупление ЗАДАЧ с РЕСУРСАМИ.
ЗАДАЧА - (хор.род) полноправно-полномочный представитель ПРИКЛАДНОЙ ПРОГРАММЫ, на который начисляются РЕСУРСЫ (если таковые есть в наличии).
ПРИКЛАДНАЯ ПРОГРАММА - (ж.род) озадачивание СИСТЕМЫ.
РЕСУРС - (дфц.род) то, чего не хватает на всех. "Начисление" сиих на ЗАДАЧУ может превратиться в "ожидание" или "разломание" последней, в зависимости от ДИСЦИПЛИНЫ управления РЕСУРСАМИ.
ДИСЦИПЛИНА - (никак.род) способность читать любую абракадабру (см.).
ПЕДАНТИЧНЫЕ ЛЮБИТЕЛИ ТОЧНЫХ ОПРЕДЕЛЕНИЙ - (ср.род ед.ч.) считают, что этот коротенький словарик - сплошной КУРАЖ (см.); а потому читать (и см.) дальше не будут.
ТЕМ, КОГО НЕ ОСТАНОВИЛО пред[ыдущее]остережение, советуем в качестве дополнения к обширным и общезначимым определениям, кои будут далее наполняться все б о л е е и б о л е е глубоким смыслом, воспользоваться также руководством по внутренней структуре файловой системы. (Мы его никогда не читали (да и не видали вовсе), но точно знаем, что оно-то существует а потому забыли название ("ищущий да обрящет")).
НУ ПОЕХАЛИ; С БОГОМ... (син. "ну и Бог с ним...").
Глава 8.1. Виды файлов
Существует три основных вида файлов: обычные файлы, директории и устройства. Устройства, в свою очередь, бывают трех категорий: диски, терминалы (клавиатуры) и специальные. С точки зрения системы управления файлами, все три вида файлов являются никак не структурированными одномерными массивами байтов.
8.1.1. Обычные файлы
Обычными (ordinary) файлами называются все файлы, не являющиеся директориями или устройствами. После открытия они предоставляются прикладным программам для чтения и записи информации (произвольной природы и длины) с произвольной байтовой позиции. Обычные файлы можно рассматривать как одномерные энергонезависимые байтовые массивы изменяемого размера.
Примечание. | Под энергонезависимостью понимается свойство не изменяться при выключении источника энергии |
8.1.2. Директории
Директории обеспечивают отображение (paths) имен файлов в сами файлы и индуцируют древовидную структуру на файловой системе в целом. В целях обеспечения целостности структуры файлового дерева непосредственное изменение содержимого директорий недоступно для пользовательских программ и выполняется только под контролем самого BIO. Директории можно (но не рекомендуется) читать как обычные файлы. В различных реализациях системы внутренний формат директорий может быть различным, а операция dir_walk позволит сделать программы, итерирующие директории, универсальными и не зависящими от этого формата.
8.1.3. Файлы-устройства
Файлы-устройства (специальные файлы) обеспечивают непосредственный доступ к управлению устройствами. Каждое поддерживаемое в BIO устройство ввода/вывода ассоциировано хотя бы с одним специальным файлом. Специальные файлы можно читать и писать как обычные файлы, но результатом запроса на запись или чтение (или выполнение операции управления устройством) будет активация соответствующего устройству драйвера вместо нормального механизма чтения/записи обычных файлов.
Вот неполный перечень выгод от унификации устройств как файлов:
- ввод и вывод у файлов и устройств схожи друг с другом настолько, насколько это возможно;
- имена файлов и устройств имеют одинаковый синтаксис и значение; таким образом, программам, ожидающим имя файла в качестве параметра, может быть с успехом передано имя некоторых устройств, а иногда и наоборот;
- на устройства распространяется общий механизм защиты от несанкционированного доступа;
- поскольку ввод и вывод унифицированы, один и тот же набор операций может быть использован и для файлов, и для устройств.
Устройства делятся на три важные категории: структурированные (или, по традиции, диски), неструктурированые (по традиции - терминалы и сериальные устройства) и специальные.
... не все файлы одинаковы, и следует считать, что в этом (возможно, не всегда выгодном) их свойстве отражено все многообразие проявлений ... мира
Глава 8.2. Параллелизм
Все операции над файлами защищены от одновременного их использования в нескольких задачах. Если с файлом работают более, чем одна задача, то система обеспечивает взаимное исключение задач при исполнении любых операций над этим файлом.
Тем не менее, BIO не обеспечивает взаимного исключения процессов (threads) одной задачи при выполнении операций над файлами. Кроме этого, BIO использует глобальные переменные задачи для информирования прикладной программы о своем состоянии. Поэтому, если в прикладной программе необходимо совместное использование несколькими процессами операций из BIO, данная программа обязана позаботиться о синхронизации и взаимном исключении этих процессов, в противном случае последствия одновременного выполнения операций (даже над разными файлами) могут быть непредсказуемо печальны.
... .... .... (Гай Юлий Цезарь)
Глава 8.3. Корневая и текущая директории
При исполнении любой программы в системе существует два предопределенных файла: корневая (root) и текущая (current) директории. Корневая директория определяется в процессе загрузки системы и обычно не изменяется по ходу работы системы. Текущая директория может быть изменена любой прикладной программой по ее усмотрению на любую (доступную) другую.
В некоторых исключительных ситуациях (при автономном (stand-alone) исполнении прикладной программы) эти две директории могут оказаться недоступными.
BIO поддерживает открытым файл текущей директории (cd). Корневая директория может быть открыта нормальным способом.
При запуске задач ими наследуется текущая директория. Каждая задача имеет свою независимую текущую директорию, и смена ее никак не сказывается на других задачах.
Корневая директория может быть сменена только привилегированным пользователем, и ее смену ощутят сразу все задачи (ежели попытаются воспользоваться корневой директорией).
... "Смотри в КОРЕНЬ!" (Козьма Пр.)
Глава 8.4. Имена файлов
- Они, конечно, откликаются, если их позвать? - небрежно заметил Комар.
- Я не знала, что они умеют... откликаться.
- Зачем же им имена, - возразил Комар, - если они на них не откликаются?
Л.Кэрролл. Алиса в Зазеркалье
8.4.1. Маршрут
Когда прикладная программа передает системе имя файла, последнее может быть специфицировано как маршрут (pathname). Маршрут есть последовательность имен директорий, разделенных символом "/", заканчивающаяся именем файла. Последовательность директорий, предшествующую имени файла, назовем префиксом. Собственно имя файла будем иногда называть последним именем маршрута.
Примечание. | Ранее вместо слова "маршрут" (pathname) мы использовали не совсем удобный термин "полное имя файла", а также употребляли не вполне корректный термин "путь", заимствованный из ОС UNIX. Далее словом под словом "путь" (path) мы будем понимать именно путь поиска файла, а именно, упорядоченное множество маршрутов. |
8.4.2. Поиск от корня
В системе принято следующее соглашение об интерпретации маршрута: если префикс начинается с символа "/", просмотр начинается с корневой директории (root directory). Так, например,
/usr/etc/some
вынуждает систему найти на корневой директории поддиректорию "usr", потом на "usr" найти "etc" и, наконец, на "etc" найти файл "some". Файл "some" может оказаться обычным файлом, директорией или устройством.
В качестве предельного случая: маршрут "/" ссылается на саму корневую директорию.
8.4.3. Поиск от текущей директории
Любой не начинающийся с символа "/" префикс (или пустой) вынуждает систему начать поиск с текущей директории. Простейшая форма маршрута (например, "some") ссылается на файл, который система будет искать на текущей директории. Такие формы маршрутов позволяют программам быстро и просто указать файл на поддиректории, не вызывая необходимости помнить полные маршруты файлов (путь от корня).
8.4.4. Имена для текущей и материнской директорий
Стандартные имена "." и ".." всегда ссылаются на саму директорию и директорию, содержащую данную, соответственно. При этом имя ".." можно итерировать, двигаясь от матери к бабушке и далее к корневой директории. Имя ".." на корневой директории ссылается на нее самое.
Примечание. | Корневая директория и директория, на которой смонтирован носитель, могут не содержать имени ".." в случае монтирования носителя, записанного в старых версиях системы. |
8.4.5. Именование файла
Имя файла состоит из 31 или менее символов и завершается байтом с кодировкой 000c (32 bytes null terminated string). Символы в имени файла могут быть любые, кроме следующих запрещенных:
ПРОБЕЛ " " SPACE 040c
СЛЭШ "/" SLASH 057c
ДВОЕТОЧИЕ ":" 072c
НУЛЬ NULL 000c
Допустимо (но не рекомендуется) использование символов с кодировками 000c..037c и 200c..377c, так как такое имя файла можно отобразить не на всяком терминале.
8.4.6. О привязанностях
В дальнейшем элемент директории, состоящий из имени файла и ссылки на файл, будет частенько называться "входом" (entry).
Если директория содержит вход (entry) с некоторым именем, ссылающийся на файл, то говорят, что этот файл "привязан" к директории под этим именем.
Возможно существование нескольких ссылок на файл из различных директорий. В таком случае говорят, что файл привязан к нескольким директориям и "счетчик связей" файла больше единицы. Файл считается уничтоженным тогда, когда исчезла последняя ссылка на него, т.е. он отвязан от всех директорий, к которым был привязан.
Попытка привязать файл к директории, находящейся на другом носителе (не на том, на котором расположен сам файл), приведет к ошибке ПЕРЕКРЕСТНАЯ ССЫЛКА (XCROSS), и файл привязан не будет.
Поскольку директория содержит ссылку ".." на родительскую директорию, она не может быть привязана более чем к одной директории. Попытка привязать директорию приведет к возбуждению ошибки ЭТО ДИРЕКТОРИЯ (IS DIRECTORY).
Глава 8.5. Хранение файлов
Свойством длительного (и иногда надежного) сохранения информации обладают обычные файлы и структурированные устройства (некоторые специальные устройства также могут обладать этим свойством).
Структуированое устройство представляет собой массив байтов фиксированной длины, из(в) которого(ый) можно прочесть(записать) последовательность байтов требуемого рамера. При выходе операции чтения/записи за границы установленного на специальном устройстве носителя возбуждаются ошибки ПЛОХОЙ ПАРАМЕТР (BAD PARAMETER) или НЕПРАВИЛЬНЫЙ АДРЕС НА УСТРОЙСТВЕ (ILLEGAL DEVICE ADDRESS).
Большинство известных структурированых устройств не требует, чтобы читаемые данные были когда-либо записаны до момента чтения. Для тех, что требуют этого (некоторые типы ОЗУ-дисков - RAM-disks), в случае чтения данных, которые ранее никогда не писались, может возникать ошибка НЕТ ДАННЫХ (NO DATA) или другие ошибки.
Обычные файлы хранятся в файловых системах, располагающихся на смонтированных носителях, установленных на структурированных устройствах. Текущая реализация накладывает ограничение на максимальный размер одного файла - он не превышает 33,554,432 байта. Файл является одномерным байтовым массивом, но его длину можно увеличивать. Увеличение длины файла производится либо явной операцией, либо автоматически при попытке записи данных за концом файла. Длину файла можно также уменьшать.
Обычные файлы хранятся неплотно. В связи с этим из них можно прочитать только те данные, которые в них были когда-либо записаны. При попытке чтения не записанных ранее данных может возникнуть ошибка НЕТ ДАННЫХ (NO DATA) или получена бессмысленная информация. При отведении места на носителе под файл учитывается размер "блокировки" данного носителя. Размер блокировки любого носителя можно узнать, выполнив соответствующую операцию. Чтение и запись файлов производятся наиболее эффективно с позиций, кратных размеру блока на данном носителе. Чтение и запись с некратных позиций могут также оказаться весьма приемлемы по эффективности при достаточно большой длине запросов на ввод/вывод. Наименее эффективными могут оказаться чтение и запись маленьких порций информации с произвольных позиций большого файла.
Файловая система гарантирует правильное хранение содержимого файла от его первого байта до конца файла (eof) при выполнении любых операций чтения/записи. Сохранность данных, оказавшихся за концом файла (eof) в результате перестановки последнего, не гарантируется.
Глава 8.6. Защита файлов
Каждому пользователю в системе присвоен уникальный идентификатор пользователя (user identification) и идентификатор его группы (group identification). Идентификаторы пользователя и группы наследуются всеми запускаемыми пользователем задачами. При создании файл помечается идентификаторами пользователя и группы его владельца. Для созданного файла устанавливается маска защиты (creation mask), которая независимо специфицирует права чтения, записи и исполнения для владельца файла (owner), других членов этой же группы, а также всех остальных, не попавших в первые две категории. Для директорий право на исполнение интерпретируется как право на "просмотр" (directory walk) содержимого директории.
Два дополнительных бита специфицируют необходимость смены идентификатора пользователя и группы при запуске задачи на базе данного кодофайла.
Владельцем файла, таким образом, является ПОЛЬЗОВАТЕЛЬ (а это - нечто абстрактное, живущее вне системы), и для простоты далее будет говорится о программах, являющихся владельцами файлов, что следует понимать как "программы, запущенные программами, запущенные программами, ..., имевшими код пользователя, равный коду владельца файла".
При интерпретации маршрута проверяется, что все директории, указанные в префиксе, доступны задаче по чтению.
При открытии и создании файла прикладная программа должна указать необходимые ей права доступа к файлу. В момент открытия (создания) проверяется возможность такого доступа, и если она отсутствует, возбуждается ошибка НАРУШЕНИЕ СЕКРЕТНОСТИ (SECURITY VIOLATION) и открытия (создания) не происходит.
В случае удачного открытия права доступа программы к файлу сохраняются и не изменяются даже при изменении идентификатора пользователя (группы) этой программы или изменении фактических прав доступа к файлу. В случае попытки применения к файлу операции, противоречащей правам доступа к файлу, установленным в момент его открытия, такая операция отклоняется, и возбуждается ошибка ЗАПРЕЩЕННЫЙ ДОСТУП (ILLEGAL ACCESS).
Права доступа к файлу ассоциированы с самим файлом, и в случае, если он привязан в нескольких местах файлового дерева (см. link), изменение прав доступа к файлу одинаково заметно во всех других точках привязки файла.
... "Безобразия нарушать вздумали?" (Неизвестный)
Глава 8.7. Библиотека BIO
Переходим к непосредственному комментированию библиотеки BIO, являющейся интерфейсом файловой подсистемы.
--------------------------------
| TYPE FILE; VAL null: FILE; |
--------------------------------
Все операции ввода/вывода применяются к объектам типа FILE, а не к самим файлам.
Значения [абстрактного] типа FILE можно породить, создавая или открывая ВНЕШНИЙ ФАЙЛ, и уничтожить, закрывая его.
Следует избегать прямого присваивания переменных типа FILE операцией ":=", поскольку после закрытия файла значения всех переменных, ссылающихся на данный файл, становятся нехорошими, их дальнейшее использование может привести в лучшем случае к ошибке "ПЛОХОЙ ДЕСКРИПТОР" (bad_desc), в худшем - к обращению к другому файлу.
Значение null для типа ФАЙЛ является предопределенным неопределенным значением. Любая операция ввода/вывода или управления файлом над файловым значением null всегда приводит к возникновению ошибки "ПЛОХОЙ ДЕСКРИПТОР" (bad_desc).
... это вам файл! а не здесь ... (Неизвестный)
------------------------------------
| VAL done: BOOLEAN; |
| error: INTEGER; |
| ename: ARRAY [0..31] OF CHAR; |
------------------------------------
При успешном завершении любой операции переменная done принимает значение TRUE, значения переменных error и ename не изменяются.
Если при выполнении какой-либо операции возникли ошибки, переменная done принимает значение FALSE, значение переменной error соответствует одной из произошедших ошибок. При множественных ошибках невозможно достоверно предсказать не зависящим от реализации способом, какая из ошибок будет зафиксирована. Система придерживается стратегии фиксирования наиболее "важной" ("суровой") из ошибок. В случае, если известно имя файла, в результате операции над которым произошла ошибка, оно записывается в ename. В тех случаях, когда оно не известно, в ename заносится специальное значение "UNKNOWN" (например, в случае ошибки "ПЛОХОЙ ДЕСКРИПТОР").
Система всегда пытается аннулировать результаты ошибочно завершившейся операции. При ошибках ввода/вывода важной дополнительной информацией является длина удачно обработанной части данных iolen (подробности см. далее).
... "Все в мире имеет конец, даже несчастия" (Г.Х.Андерсен)
8.7.1. Общие замечания
BIO содержит набор операций, парных друг к другу, позволяющих интерпретировать маршрут относительно текущей директории (cd) или произвольной директории (рассматривая ее как текущую). Такие операции будут описываться парами, например:
dosomething( ... path: ARRAY OF CHAR ...);
fdosomething(cd: FILE; ... path: ARRAY OF CHAR ...);
при этом следует иметь в виду, что выполнение операции
dosomething(...)
полностью эквивалентно выполнению операции
fdosomething(BIO.cd,...)
и попросту является его удобным сокращением.
Все вышесказаное следует относить только к операциям, описание которых дается парно, и не следует распространять на другие похожие по звучанию и написанию имена операций (например, read, fread; write, fwrite и т.п.)
Все операции, имеющие в качестве аргумента маршрут, интерпретируют его префикс. Все имена в префиксе должны ссылаться на директории (иначе возбуждается ошибка ЭТО НЕ ДИРЕКТОРИЯ). Все директории в префиксе должны быть доступны по чтению. Если чтение запрещено, возбуждается ошибка НАРУШЕНИЕ СЕКРЕТНОСТИ (SECURITY VIOLATION).
Операции открытия и создания файла имеют в качестве параметра также способ открытия файла (mode), который определяет набор операций, применимых к открытому файлу, и способ их применения. Способ открытия - это строка из символов (специфичных для каждой операции), приведенных в произвольном порядке. Символы, не наделенные семантикой для данной операции, игнорируются, не приводя к возбуждению ошибки.
8.7.2. Об ошибках
Везде далее за описанием той или иной операции будет следовать описание ошибок, которые могут возникнуть в процессе ее исполнения. Главным признаком ошибки является ее английская аббревиатура, соответствующая общесистемному коду ошибки. Пользователь (или программа) может получить также название ошибки на русском, английском (или другом) языке, в зависимости от установленного языкового драйвера. Такие названия здесь приводятся прописными буквами. Они никоим образом не являются делом файловой системы и в принципе могут несколько отличаться от используемых в текущей реализации ОС Excelsior.
При выполнении практически любой операции над файлами возможно возникновение следующих ошибок (поэтому эти ошибки не описываются отдельно для каждой операции):
ПЛОХОЕ ИМЯ bad_name
Имя файла либо
содержит недопустимые символы, либо пустое или слишком длинное.
ПЛОХОЙ ДЕСКРИПТОР bad_desc
В качестве значения
типа FILE использовано неправильное значение, неоткрытый
(или уже закрытый) файл, значение BIO.null или испорченное значение.
НЕТ ПАМЯТИ no_memory
Нет свободной памяти
для порождаемых в ходе выполнения операции структур данных.
НАРУШЕНИЕ СЕКРЕТНОСТИ sec_vio
Невозможно открыть
или создать файл с указанными правами доступа, или нет права чтения директории,
встретившейся в префиксе маршрута.
ЗАПРЕЩЕННЫЙ ДОСТУП ill_access
Права доступа к файлу
не позволяют применить к нему данную операцию.
НЕПОДХОДЯЩИЙ unsuitable
Объект, к которому применяется
операция, не является объектом подходящего класса (например, операция make file system неприменима
к файлу, являющемуся сериальным устройством).
ПРЕРВАННАЯ ОПЕРАЦИЯ ipted_op
Операция была прервана
в результате того, что задаче, запросившей операцию, был послан сигнал kill.
НЕПРАВИЛЬНАЯ ОПЕРАЦИЯ ill_op
Данная операция не применима
к этому объекту или не реализована в драйвере устройства, с которым
ассоциирован (или на котором хранится) этот объект.
ОШИБКА ВВОДА/ВЫВОДА io_error **
При выполнении операции
ввода/вывода информации драйвер или контроллер устройства зафиксировали нарушения
в работе оборудования.
ПЛОХАЯ ФАЙЛОВАЯ СИСТЕМА bad_fsys **
При работе с файловой
системой на дисковом устройстве обнаружены ошибки в ее логической организации.
Требуется немедленное прекращение работы с данной файловой системой, тщательная
ее проверка и, возможно, коррекция и восстановление.
НЕ ОПРЕДЕЛЕНО undef **
Устройство, над котором
должна быть выполнена операция (или на котором располагается файл) ЕЩЕ или УЖЕ
не определено. Устройство может быть ЕЩЕ не определено в момент, когда драйвер устройства
уже прошел стадию регистрации, но еще не представил системе свой обработчик запросов
на ввод/вывод. Устройство может быть УЖЕ не определено в момент, когда драйвер
устройства завершил свою работу (например, в связи с поломкой устройства или ошибкой
в самом драйвере, приведшей к его аварийной остановке), а задача еще
располагает открытыми на этом устройстве файлами. Устойство полностью исчезнет из
системы только после завершения драйвера и закрытия всех файлов на этом
устройстве.
Здесь и везде далее двумя звездочками (**) помечены ошибки, предсказать результаты операции при возникновении которых достаточно сложно и они могут оказаться самыми различными. В таких ситуациях файловая система на носителе, или устройство, или контроллер устройства, или процессор требуют специфического обслуживания (maintenance) или ремонта (re mount).
Если в описании операции не растолкована возбуждаемая ошибка, а только указано ее название - это означает, что причина возбуждения ошибки совпадает с описанной здесь.
8.7.3. chdir, chroot
-------------------
| VAL cd: FILE; |
-------------------
В переменной cd [почти] всегда содержится открытый файл текущей директории. Переменная cd инициализируется в момент запуска задачи путем открытия директории с маршрутом, взятым из ОКРУЖЕНИЯ (Environment), по имени "CD". В случае неудачного открытия cd переставляется на корневую директорию.
Непосредственно после запуска задачи и до первого обращения к любой процедуре из BIO переменная done является результатом попытки открытия текущей директории, и в случае если done=FALSE, переменная error содержит код ошибки открытия этой директории.
PROCEDURE chdir(path : ARRAY OF CHAR);
--------------------------------------
Переставляет директорию cd на директорию, указанную маршрутом path. В случае ошибки cd остается на прежнем месте.
Возможные ошибки:
ЭТО НЕ ДИРЕКТОРИЯ not_dir
имя в префиксе
маршрута или сам маршрут указывают не на директорию;
НЕТ ТАКОГО no_entry
не найдена
директория [из маршрута] с таким именем;
ПЛОХОЕ ИМЯ bad_name
НЕТ ПАМЯТИ no_memory
НАРУШЕНИЕ СЕКРЕТНОСТИ sec_vio
ПЛОХАЯ ФАЙЛОВАЯ СИСТЕМА bad_fsys **
ОШИБКА ВВОДА/ВЫВОДА io_error **
НЕ ОПРЕДЕЛЕНО undef **
PROCEDURE chroot(path : ARRAY OF CHAR);
---------------------------------------
Переставляет корневую директорию файловой системы на директорию, указанную маршрутом path. В случае ошибки корневая директория остается на прежнем месте. Эта процедура может быть выполнена только привилегированным пользователем.
Возможные ошибки:
ЭТО НЕ ДИРЕКТОРИЯ not_dir
имя в префиксе
маршрута или сам маршрут указывают не на директорию;
ДЛЯ ПРИВИЛЕГИРОВАННЫХ su_only
эта операция
разрешена только в привилегированном режиме;
НЕТ ТАКОГО no_entry
не найдена
директория [из маршрута] с таким именем;
ПЛОХОЕ ИМЯ bad_name
ПЛОХОЙ ДЕСКРИПТОР bad_desc
НЕТ ПАМЯТИ no_memory
НАРУШЕНИЕ СЕКРЕТНОСТИ sec_vio
ПЛОХАЯ ФАЙЛОВАЯ СИСТЕМА bad_fsys **
ОШИБКА ВВОДА/ВЫВОДА io_error **
НЕ ОПРЕДЕЛЕНО undef **
8.7.4. fname, splitpathname
PROCEDURE fname (file: FILE; VAR name: ARRAY OF CHAR);
PROCEDURE splitpathname(VAR path: ARRAY OF CHAR; VAR name: ARRAY OF CHAR);
---------------------------------------------
Операция fname выдает полное имя файла (с указанием маршрута от корня).
Операция splitpathname позволяет выделить из имени маршрута префикс и последнее имя.
При применении операции параметр path должен содержать спецификацию маршрута. После успешного применения операции в параметре path остается префикс маршрута, в переменную name заносится последнее имя. Префикс может оказаться пустым.
Если при выделении префикса или имени в них обнаружены символы, запрещенные к использованию в именах файлов, а также если последнее имя или одно из имен директорий в префиксе состоит более чем из 31 символа, возбуждается ошибка ПЛОХОЕ ИМЯ (BAD NAME).
Переменная name после успешного завершения операции обязательно содержит непустую строку символов, которая обязательно завершается байтом с кодом 000c.
Если объем переменной name не достаточен для вмещения последнего имени, то имя усекается без возбуждения ошибки.
Возможно возникновение ошибок:
ПЛОХОЕ ИМЯ bad_name
8.7.5. equal, open, fopen
PROCEDURE equal(f0,f1: FILE): BOOLEAN;
--------------------------------------
Возвращает TRUE, если файловые переменные f0,f1 ссылаются на один файл, иначе FALSE.
PROCEDURE open (VAR file: FILE; path,mode: ARRAY OF CHAR);
PROCEDURE fopen(cd: FILE;
VAR file: FILE; path,mode: ARRAY OF CHAR);
----------------------------------------------------------
Операции open,fopen позволяют открыть файл, директорию, устройство для дальнейшей работы с ними.
Операция open является точным эквивалентом операции fopen(BIO.cd,.....).
Path содержит маршрут и имя открываемого файла. Open открывает файл и устанавливает права и методы доступа в соответствии с mode. В случае успешного открытия порождает и возвращает новое значение типа FILE. Указатель текущей позиции устанавливается в начало файла (если не указано обратное).
Значение mode конструируется в соответствии со следуюшим списком:
- 'r' (read) файл открывается для чтения;
- 'w' (write) файл открывается для записи;
- 'm' (modify) файл открывается для чтения и записи;
- 'x' (execute) файл открывается для исполнения/просмотра;
- 'X' (eXelent) файл открывается c максимально возможными правами доступа;
- 'а' (append) после открытия файла указатель текущей позиции установится в конец файла;
- 'd' (direct write) ожидание завершения записи;
- 'n' (nodelay) чтение без ожидания (читается столько, сколько есть в буфере (для последовательных и специальных устройств);
- 'c' (no casch) выключение кэша, чтение всегда с диска и прямая запись (для обычных файлов).
Открытие файла совсем без доступа по чтению/записи может оказаться полезным для опроса или изменения его атрибутов (особенно тогда, когда чтение/запись запрещены) или для итерации (прогулке по) директории.
Возможно возникновение ошибок:
ЭТО НЕ ДИРЕКТОРИЯ not_dir
имя в префиксе
маршрута указывает не на директорию, или значение cd
не является директорией;
ПЛОХОЙ ДЕСКРИПТОР bad_desc
плохое значение
параметра или переменной cd;
НЕТ ТАКОГО no_entry
на директории, указанной
маршрутом, не найден файл с указанным именем, или не найдена директория для
одного из имен в префиксе маршрута;
НЕТ ПАМЯТИ no_memory
НАРУШЕНИЕ СЕКРЕТНОСТИ sec_vio
ПЛОХОЕ ИМЯ bad_name
ПРЕРВАННАЯ ОПЕРАЦИЯ ipted_op
ПЛОХАЯ ФАЙЛОВАЯ СИСТЕМА bad_fsys **
ОШИБКА ВВОДА/ВЫВОДА io_error **
НЕ ОПРЕДЕЛЕНО undef **
В случае возникновения ошибки файл 'file' не открываетсяи возвращается значение BIO.null.
Привилегированному пользователю (superuser), и только ему, предоставляется возможность открытия файлов устройств, для которых нет соответствующих узлов в файловом дереве (см. mknode). Для этого необходимо в качестве имени открываемого файла указать имя логического устройства, предваренное символом ":". Из-за отсутствия узла в файловом дереве (а соответственно, и списка прав доступа к устройству) такое открытие вскрывает устройство с полным набором прав (все дозволено). Такой способ открытия необходим и применяется только при установке системы на новое оборудование и при установке корня файловой системы после загрузки ОС.
8.7.6. create, fcreate, chmode
VAL cmask: BITSET;
PROCEDURE create (VAR file: FILE; path,mode: ARRAY OF CHAR; size: INTEGER);
PROCEDURE fcreate(cd: FILE; VAR file: FILE; path,mode: ARRAY OF CHAR; size: INTEGER);
-------------------------------------------------------------
Операции create, fcreate позволяют создать постоянный или временный файл на носителе, смонтированном на структурированном устройстве.
Операция create является точным эквивалентом операции fcreate(BIO.cd,.....).
Path содержит маршрут и имя создаваемого файла. Create создает файл и устанавливает права и методы доступа в соответствии с mode. В случае успешного создания порождает и возвращает новое значение типа FILE.
Указатель текущей позиции устанавливается в начало файла (если не указано обратное). Указатель конца файла eof также стоит в начале.
Файл всегда создается на носителе, на котором расположена директория cd.
Параметр size задает размер (в байтах) пространства на носителе, которое должно быть предварительно (в момент создания) выделено для файла. Если создание файла прошло успешно, в файл гарантированно возможно записать минимум size байт информации. Параметр size не фиксирует максимальный размер файла (ограниченный, главным образом, размером свободного пространства на носителе). Он только указывает минимальный необходимый размер файла, известный программе. Если таковой неизвестен, можно смело использовать значение 0.
Вне зависимости от параметра size после операций create, fcreate указатель конца файла (eof) всегда установлен в 0.
Имя файла может быть пустым. В таком случае создается временный файл, который будет уничтожен после закрытия (если до этого не будет "привязан" см. link).
Нельзя создать файл с именами "." и ".."; в этом случае возбуждается ошибка ПЛОХОЕ ИМЯ (BAD NAME).
В момент создания запоминается имя файла и директория, на которую указывал маршрут. Привязывание файла к директории произойдет только в момент его ЗАКРЫТИЯ. Вплоть до закрытия файла на директории, где он создан, будет сохраняться (ежели наличествует) файл с таким же именем.
Имя файла, оставшееся в path после интерпретации префикса, должно состоять не более чем из 31 символа и завершаться 0с. В случае более длиного имени оно усекается до 31 символа (без возбуждения ошибок). Ошибка ПЛОХОЕ ИМЯ (BAD NAME) возбуждается в том случае, если в имени файла обнаружены символы, запрещенные к использованию в именах файлов (см. ранее).
Если файл не будет закрыт самой программой, то по ее окончании (как аварийном, так и нормальном) файл будет закрыт БЕЗ привязывания к директории (purge).
Значение переменной cmask (creation mask) определяет права доступа к файлу после его привязывания. См. также операцию chcmask.
Значение mode конструируется в соответствии со следуюшим списком:
- 'r' (read) файл создается для чтения;
- 'w' (write) файл создается для записи;
- 'm' (modify) файл создается для чтения и записи;
- 'x' (execute) файл создается для исполнения/просмотра;
- 'X' (eXelent) файл создается c максимально возможными правами доступа;
- 'd' (direct write) ожидание завершения записи;
- 'n' (nodelay) чтение без ожидания (читается столько, сколько есть в буфере (для последовательных и специальных устройств);
- 'c' (no casch) выключение кэша, чтение всегда с диска и прямая запись (для обычных файлов);
- 'h' создать файл с признаком hidden (в момент закрытия файл будет привязан как "невидимый").
Права доступа к файлу задачи, создавшей его, определяются значением параметра mode вплоть до закрытия файла. Значение cmask не влияет на права доступа к файлу задачи, создавшей файл. Оно будет использовано только в случае, если какая-либо задача (в том числе и создавшая его) попытается открыть его после (закрытия и) привязывания.
Возможно возникновение ошибок:
ЭТО НЕ ДИРЕКТОРИЯ not_dir
имя в префиксе
маршрута указывает не на директорию, или значение cd
не является директорией;
НЕТ СВОБОДНОГО МЕСТА no_space
на носителе, где создается
файл, нет требуемого свободного пространства размером size
байт;
НОСИТЕЛЬ ПЕРЕПОЛНЕН fsys_full
на носителе, где создается
файл, переполнена таблица файлов;
ПЛОХОЙ ДЕСКРИПТОР bad_desc
плохое значение
параметра или переменной cd;
НЕТ ТАКОГО no_entry
не найдена директория
для одного из имен в префиксе маршрута;
НЕТ ПАМЯТИ no_memory
НАРУШЕНИЕ СЕКРЕТНОСТИ sec_vio
ПЛОХОЕ ИМЯ bad_name
ПРЕРВАННАЯ ОПЕРАЦИЯ ipted_op
ПЛОХАЯ ФАЙЛОВАЯ СИСТЕМА bad_fsys **
ОШИБКА ВВОДА/ВЫВОДА io_error **
НЕ ОПРЕДЕЛЕНО undef **
В случае возникновения ошибки файл 'file' не создается и возвращается значение BIO.null.
..."Сделайте мне красиво ..." ...
8.7.7. du, dup
PROCEDURE du(cd: FILE; VAR free,used: INTEGER);
-----------------------------------------------
Операция du (disk usage) позволяет узнать размер свободного и занятого пространства (в байтах) на носителе, на котором расположена указанная директория.
Возможно возникновение ошибок:
ЭТО НЕ ДИРЕКТОРИЯ not_dir
значение cd не является директорией;
PROCEDURE dup(VAR new: FILE; file: FILE);
-----------------------------------------
Операция dup предназначена для порождения нового значения типа FILE путем копирования уже имеющегося значения.
Создает новое значение типа FILE, которое ссылается на тот же файл, что и file. Для файла заводится новый указатель позиции, новые права доступа и новое множество (изначально пустое) буферов ввода/вывода.
Указатель позиции, права доступа и число возможных буферов ввода/вывода копируются из файла file.
Если файл file был создан операцией create, НЕ происходит копирования в значение new имени (под которым нужно будет привязать файл) и директории (к которой нужно будет привязать файл в момент его закрытия).
В случае отсутствия буферизации можно использовать новое значение new как дополнительный указатель текущей позиции ввода/вывода, т.к. в этом случае все изменения содержимого (и указателя конца) в любой из этих двух копий немедленно становятся доступны и для другой.
Файл file может быть и директорией. Если эта директория итерировалась с помощью dir_walk (см.) в момент дублирования, это никак не скажется на ее дубликате.
Закрытие файла file операциями close или purge никак не сказывается на его дубликате.
Возможные ошибки:
ПЛОХОЙ ДЕСКРИПТОР bad_desc
плохое значение
параметра file;
НЕТ ПАМЯТИ no_memory
8.7.8. close, purge
PROCEDURE close (VAR file: FILE);
PROCEDURE purge (VAR file: FILE);
---------------------------------
Операции purge и close закрывают файл, делая невозможным дальнейшее выполнение операций над ним.
Процедуры purge и close работают абсолютно одинаково для всех файлов, кроме созданных процедурами create, fcreate.
Файлы, созданные процедурами create и fcreate, процедура purge закрывает безусловно, не пытаясь привязать к директории.
Если файл был открыт или создан с пустым именем (см. create), close тоже просто закрывает его. Иначе close пытается привязать файл к директории, и закрывает его, если только это удалось. В случае ошибки привязывания файл остается открытым (file#BIO.null), и прикладная программа может по выбору попытаться привязать его в другое место файлового дерева или выполнить над ним операцию purge. В случае если программа так и не пришла ни к какому решению, по ее завершении над всеми созданными, но не привязанными файлами выполняется операция purge.
Если в момент закрытия или удаления файл имеет нулевое число связей (не привязан ни к одной директории), он будет удален, а пространство, занятое его данными, будет считаться свободным.
Возможно возникновение ошибок:
ЭТО ДИРЕКТОРИЯ is_dir *
при закрытии (close) и привязывании созданного операцией create файла обнаружилась непустая директория с
таким же именем;
НАРУШЕНИЕ СЕКРЕТНОСТИ sec_vio *
при закрытии (close) и привязывании созданного операцией create файла
обнаружилось нарушение прав доступа к директории;
НЕТ СВОБОДНОГО МЕСТА no_space
при закрытии (close) и привязывании созданного операцией create файла
потребовалось расширить директорию, к которой привязывается файл, и на
носителе, на котором создан файл, не хватило свободного пространства;
ПЛОХОЙ ДЕСКРИПТОР bad_desc
плохое значение
параметра file;
ПРЕРВАННАЯ ОПЕРАЦИЯ ipted_op
ПЛОХАЯ ФАЙЛОВАЯ СИСТЕМА bad_fsys **
ОШИБКА ВВОДА/ВЫВОДА io_error **
НЕ ОПРЕДЕЛЕНО undef **
Символом (**) помечены ошибки, при которых файл может остаться НЕЗАКРЫТЫМ (file#BIO.null). Во всех остальных случаях файл закрывается даже в случае возникновения ошибки, и переменной file присваивается значение BIO.null.
Примечание. | В момент удаления файла пространство, отведенное файлу, продолжает содержать ранее записанную в него информацию. Это пространство впоследствии может быть отведено под другой файл, и программа, создавшая этот другой файл, может получить доступ ко всей (или к части) информации из удаленного файла. В случае особой важности и секретности хранимой в файле информации для предотвращения такой ситуации рекомендуется перед уничтожением файла "почистить" его содержимое (например, прописав его весь байтами с кодом 000, или любыми другими, менее секретными, чем его драгоценное содержимое). |
8.7.9. link, flink
PROCEDURE link (file: FILE; path,mode: ARRAY OF CHAR);
PROCEDURE flink (cd : FILE; file: FILE; path,mode: ARRAY OF CHAR);
-------------------------------------------------------
Операции link, flink позволяют привязать файл к директории.
Операция link является точным эквивалентом операции flink(BIO.cd,.....).
Path содержит маршрут, префикс которого указывает на директорию, и имя, под которым к ней надо привязать файл.
В случае успешного привязывания счетчик связей файла увеличивается на 1.
Параметр mode может указывать на необходимость установки атрибута "скрытый" (hidden).
Значение mode конструируется в соответствии со следуюшим списком:
- 'h' привязать файл с признаком hidden ("невидимый");
- 's' привязать файл с признаком system ("системный").
Нельзя привязать:
- файл к директории, находящейся на другом носителе (ПЕРЕКРЕСТНАЯ ССЫЛКА);
- директорию (ЭТО ДИРЕКТОРИЯ);
- файл, если существует непустая директория с таким же именем (ЭТО ДИРЕКТОРИЯ);
- файл с именами "." и ".."; в этом случае возбуждается ошибка ПЛОХОЕ ИМЯ (BAD NAME).
Имя файла, оставшееся в path после интерпретации префикса, должно состоять не более чем из 31 символа и завершаться 0с. В случае более длинного имени оно усекается до 31 символа (без возбуждения ошибок). Ошибка ПЛОХОЕ ИМЯ (BAD NAME) возбуждается в том случае, если в имени файла обнаружены символы, запрещенные к использованию в именах файлов.
Для привязывания файла к директории необходимо иметь к ней доступ по записи.
Если в момент привязывания на директории существует файл (или пустая поддиректория) с таким же именем, как имя привязываемого файла, он (она) будет отвязан(а).
Возможно возникновение ошибок:
ЭТО НЕ ДИРЕКТОРИЯ not_dir
имя в префиксе
маршрута указывает не на директорию, или значение cd
не является директорией;
ЭТО ДИРЕКТОРИЯ is_dir
привязываемый файл оказался
директорией, или файл, отвязываемый вследствие привязывания, оказался непустой директорией;
НОСИТЕЛЬ ПЕРЕПОЛНЕН fsys_full
на носителе, куда
привязывается файл, переполнена таблица файлов;
НЕТ СВОБОДНОГО МЕСТА no_space
на носителе, где располагаются
файл и директория, нет свободного пространства, необходимого для увеличения размера
директории;
НЕТ ТАКОГО no_entry
не найдена директория
для одного из имен в префиксе маршрута;
ПЛОХОЙ ДЕСКРИПТОР bad_desc
плохое значение
параметра или переменной cd;
НАРУШЕНИЕ СЕКРЕТНОСТИ sec_vio
нет права записи в директорию,
к которой ведется привязывание;
ПЕРКРЕСТНАЯ ССЫЛКА xcross
файл и директория, к
которой ведется привязывание, находятся на разных носителях;
ПЛОХОЕ ИМЯ bad_name
ПРЕРВАННАЯ ОПЕРАЦИЯ ipted_op
ОШИБКА ВВОДА/ВЫВОДА io_error **
ПЛОХАЯ ФАЙЛОВАЯ СИСТЕМА bad_fsys **
НЕ ОПРЕДЕЛЕНО undef **
В результате возникновения любой ошибки (кроме помеченных **) файл остается непривязанным, а файл, который должен был быть отвязан в результате привязывания, неотвязанным.
8.7.10. unlink, funlink
PROCEDURE unlink( path: ARRAY OF CHAR);
PROCEDURE funlink(cd: FILE; path: ARRAY OF CHAR);
--------------------------------------------------
Операции unlink, funlink позволяют отвязать файл или поддиректорию от директории.
Операция unlink является точным эквивалентом операции funlink(BIO.cd,.....).
Path содержит маршрут, префикс которого указывает на директорию, и имя файла, который нужно от нее отвязать.
В случае успешного отвязывания счетчик связей файла уменьшается на 1. Если при этом он стал равным 0, происходит уничтожение файла и освобождение ранее занятого им пространства.
Нельзя отвязать:
- непустую поддиректорию;
- поддиректорию с именем ".."; в этом случае возбуждается ошибка ПЛОХОЕ ИМЯ (BAD NAME).
Для отвязывании файла от директории необходимо иметь к ней доступ по записи.
Возможно возникновение ошибок:
ЭТО НЕ ДИРЕКТОРИЯ not_dir
имя в префиксе
маршрута указывает не на директорию, или значение cd
не является директорией;
ЭТО ДИРЕКТОРИЯ is_dir
отвязываемый файл
оказался непустой директорией;
ПЛОХОЙ ДЕСКРИПТОР bad_desc
плохое значение
параметра или переменной cd;
НАРУШЕНИЕ СЕКРЕТНОСТИ sec_vio
нет права записи в
директорию, к которой осуществляется привязывание;
НЕТ ТАКОГО no_entry
на директории, указываемой
маршрутом, не найден файл с указанным именем, или не найдена директория для
одного из имен в префиксе маршрута;
ПЛОХОЕ ИМЯ bad_name
ПРЕРВАННАЯ ОПЕРАЦИЯ ipted_op
ОШИБКА ВВОДА/ВЫВОДА io_error **
ПЛОХАЯ ФАЙЛОВАЯ СИСТЕМА bad_fsys **
НЕ ОПРЕДЕЛЕНО undef **
В результате возникновения любой ошибки (кроме помеченных **) файл остается неотвязанным.
8.7.11. mkdir, fmkdir
PROCEDURE mkdir ( path: ARRAY OF CHAR; hidden: BOOLEAN);
PROCEDURE fmkdir(cd: FILE; path: ARRAY OF CHAR; hidden: BOOLEAN);
-----------------------------------------------------------------
Операции mkdir, fmkdir позволяют создать новую поддиректорию.
Операция mkdir является точным эквивалентом операции fmkdir(BIO.cd,.....).
Path содержит маршрут, префикс которого указывает на директорию, и имя поддиректории, которую нужно создать.
Параметр hidden определяет видимость/скрытость созданной директории.
В случае успешного создания поддиректории на ней автоматически создается вход с именем "..", ссылающийся на материнскую директорию. Число связей директории, тем не менее, всегда равно единице независимо от числа ее поддиректорий (содержащих на нее обратную ссылку "..").
Если при создании поддиректории на директории находился файл (или пустая поддиректория) с таким же именем, он(а) автоматически отвязывается.
При наличии непустой поддиректории с таким же именем операция создания не происходит и возбуждается ошибка ЭТО ДИРЕКТОРИЯ (IS DIRECTORY).
Для создания поддиректории необходимо иметь доступ по записи к директории, на которой происходит создание.
Нельзя создать поддиректории с именами "." и ".."; в этом случае возбуждается ошибка ПЛОХОЕ ИМЯ (BAD NAME).
Возможно возникновение ошибок:
ЭТО НЕ ДИРЕКТОРИЯ not_dir
имя в префиксе
маршрута указывает не на директорию, или значение cd
не является директорией;
ЭТО ДИРЕКТОРИЯ is_dir
отвязываемый файл
оказался непустой директорией;
ПЛОХОЙ ДЕСКРИПТОР bad_desc
плохое значение
параметра или переменной cd;
НАРУШЕНИЕ СЕКРЕТНОСТИ sec_vio
нет права записи в директорию,
к которой ведется привязывание;
НЕТ ТАКОГО no_entry
не найдена директория
для одного из имен в префиксе маршрута;
ПЛОХОЕ ИМЯ bad_name
ПРЕРВАННАЯ ОПЕРАЦИЯ ipted_op
ПЛОХАЯ ФАЙЛОВАЯ СИСТЕМА bad_fsys **
ОШИБКА ВВОДА/ВЫВОДА io_error **
НЕ ОПРЕДЕЛЕНО undef **
В результате возникновения любой ошибки (кроме помеченных **) поддиректория не создается.
8.7.12. fmvdir
PROCEDURE fmvdir(cd,to: FILE; path,name: ARRAY OF CHAR; hidden: BOOLEAN);
-------------------------------------------------------------------------
Операция fmvdir перемещает директорию с одного места в файловом дереве в другое.
Path указывает на директорию (относительно cd), которую необходимо перенести на директорию to с именем name.
Параметр hidden определяет видимость/скрытость перемещенной директории.
В случае успешного переноса директории ссылка из вход с именем ".." на ней автоматически переделывается в ссылку на директорию to. Директория отвязывается от директории, к которой она была ранее привязана. Число связей директории не изменяется. При перемещении директории вместе с ней, естественно, перемещаются и все ее потомки (поддиректории, поддиректории поддиректорий и т.д.).
Если при перемещении директории на директории to находился файл (или пустая поддиректория) с таким же именем, он(а) автоматически отвязывается.
При наличии непустой поддиректории с таким же именем при перемещении директории возбуждается ошибка ЭТО ДИРЕКТОРИЯ (IS DIRECTORY).
Для перемещения директории необходимо иметь доступ по записи к директории, содержашей данную, и к той, на которую происходит перемещение.
Нельзя переместить:
- директорию с новым именем "." и ".."; в этом случае возбуждается ошибка ПЛОХОЕ ИМЯ (BAD NAME);
- корневую директорию и директорию, на которую смонтирован носитель; в этом случае возбуждается ошибка ПЕРЕКРЕСТНАЯ ССЫЛКА (XCROSS);
- директорию между носителями; в этом случае возбуждается ошибка ПЕРЕКРЕСТНАЯ ССЫЛКА (XCROSS).
Возможно возникновение ошибок:
ЭТО НЕ ДИРЕКТОРИЯ not_dir
имя в префиксе
маршрута указывает не на директорию, или значение cd или to не
является директорией, или path указывает не на директорию;
ЭТО ДИРЕКТОРИЯ is_dir
отвязываемый файл
оказался непустой директорией;
ПЛОХОЙ ДЕСКРИПТОР bad_desc
плохое значение
переменных cd или to,
или параметра;
НАРУШЕНИЕ СЕКРЕТНОСТИ sec_vio
нет права записи в директорию,
из(к) которой ведется отвязывание(привязывание);
НЕТ ТАКОГО no_entry
не найдена директория
для одного из имен в префиксе маршрута;
ПЕРКРЕСТНАЯ ССЫЛКА xcross
попытка переместить
директорию с одного носителя на другой;
ПЛОХОЕ ИМЯ bad_name
ПРЕРВАННАЯ ОПЕРАЦИЯ ipted_op
ОШИБКА ВВОДА/ВЫВОДА io_error **
ПЛОХАЯ ФАЙЛОВАЯ СИСТЕМА bad_fsys **
НЕ ОПРЕДЕЛЕНО undef **
В результате возникновения любой ошибки (кроме помеченных **) поддиректория не перемещается.
8.7.13. check_io, buffers, seek
PROCEDURE check_io(halt_on_error: BOOLEAN);
-------------------------------------------
Операция check_io предназначена для включения/выключения аварийного завершения задачи при ошибках в операциях ввода/ вывода. По умолчанию аварийное завершение запрещено и операции ввода/вывода возвращают ошибки в случае их возникновения.
PROCEDURE buffers(file: FILE; no,size);
---------------------------------------
Буферы файла используются для буферизации чтения и записи в файл. Указание числа буферов разрешает системе (но не обязывает ее) использовать no буферов. Размер буфера (в байтах) size может округляться системой до ближайшего большего, кратного blocksize байт (см. fstype).
В случае нехватки памяти для размещения буферов возбуждается ошибка no_memory. Система обеспечивает нормальное функционирование с меньшим числом буферов и даже вовсе без буферизации.
Заметим, что в случае изготовления дубликата значения типа файл операцией dup буферы для нового значения типа файл (как и текущая позиция в файле) будут другими, нежели у исходного файла. Синхронизация некогеррентного содержимого буферов может быть достигнута выполнением операции flush после каждой записи и перед каждым чтением из файла. (Правда, при такой дисциплине использования эффективность буферизации слегка ниже нуля, и поэтому выгоднее просто не использовать буферизацию при необходимости таких приложений).
В случае отсутствия буферизации операции чтения/записи используют системную кеш-память, содержащую когерентную информацию вне зависимости от числа дубликатов дескриптора файла.
Буферизация может оказаться весьма полезной при чтении/записи файлов в построчном (getstr, putstr) или посимовльном (getch, putch) режимах. (Замечание: посимвольный режим все же существенно медленнее любых других, поэтому рекомендуется по возможности избегать его применения и пользоваться более крупноблочными операциями).
PROCEDURE seek(file: FILE; offset,origin: INTEGER);
---------------------------------------------------
Операция seek устанавливает в файле текущую позицию записи/чтения.
В зависимости от origin, значение offset задает:
- origin=0 смещение от начала файла;
- origin=1 смещение от текушей позиции;
- origin=2 смещение от конца файла.
При всех других значениях origin возбуждается ошибка ПЛОХОЙ ПАРАМЕТР (BAD PARAMETER).
Текущая позиция в файле может указывать на произвольное место (в том числе и за конец файла). Она не может быть отрицательна, и если после seek получилась отрицательная позиция, возбуждается ошибка ПЛОХОЙ ПАРАМЕТР (BAD PARAMETER).
Если текущая позиция указывает за конец файла, применение к файлу операций чтения приведет к ошибке НЕТ ДАННЫХ (NO DATA), в то время как запись с этой позиции приведет к автоматическому расширению файла до нужных размеров и перестановке указателя конца файла (eof). При этом значения байтов между старым и новым значениями указателя конца файла могут быть не определены и даже вовсе отсутствовать (так называемый неплотный файл).
Для специальных файлов (неструктурированных устройств), кроме устанавления позиция чтения/записи, происходит обращение к драйверу специального устройства с запросом на операцию SEEK. Если операция SEEK не реализована в драйвере, будет возбуждена ошибка НЕПРАВИЛЬНАЯ ОПЕРАЦИЯ.
Возможно возникновение ошибок:
ПЛОХОЙ ДЕСКРИПТОР bad_desc
неоткрытый, или уже
закрытый, или испорченный file;
ПЛОХОЙ ПАРАМЕТР bad_parm
неправильное
значение параметров origin или offset;
ПРЕРВАННАЯ ОПЕРАЦИЯ ipted_op
НЕПРАВИЛЬНАЯ ОПЕРАЦИЯ ill_op
ОШИБКА ВВОДА/ВЫВОДА io_error **
НЕ ОПРЕДЕЛЕНО undef **
8.7.14. pos, eof
PROCEDURE pos (file: FILE): INTEGER;
PROCEDURE eof (file: FILE): INTEGER;
------------------------------------
Операция pos возвращает текущее положение указателя чтения/записи в файле.
Операция eof возвращает текущий размер файла.
Указатель позиции чтения/записи может перемещаться по файлу в результате выполнения операций чтения/записи и операции seek. С помощью операции pos можно узнать текущее положение указателя чтения/записи.
Для неструктурированных устройств позиция также хранится и может изменяться в результате выполнения операций чтения/записи и операции seek. Применение операции doio() никак не влияет на указатель чтения/записи, даже если на устройстве действительно выполнялась операция обмена.
Операция eof выдает число, равное максимальному номеру байта в файле плюс единица. Для структурированных устройств eof выдает размер устройства в байтах. Для неструктурированных устройств происходит обращение к драйверу устройства с запросом READY, что позволяет программе узнать число байтов, готовых к чтению, в буфере ввода. Если операция READY не реализована в драйвере, будет возбуждена ошибка НЕПРАВИЛЬНАЯ ОПЕРАЦИЯ.
Возможно возникновение ошибок:
ПЛОХОЙ ДЕСКРИПТОР bad_desc
неоткрытый, или уже
закрытый, или испорченный file;
ПРЕРВАННАЯ ОПЕРАЦИЯ ipted_op
НЕПРАВИЛЬНАЯ ОПЕРАЦИЯ ill_op
ОШИБКА ВВОДА/ВЫВОДА io_error **
НЕ ОПРЕДЕЛЕНО undef **
8.7.15. fread, fwrite, read, write, get, put
VAL iolen: INTEGER;
PROCEDURE fread (f: FILE; buf: ADDRESS; pos,len: INTEGER);
PROCEDURE fwrite (f: FILE; buf: ADDRESS; pos,len: INTEGER);
PROCEDURE read (f: FILE; buf: ADDRESS; len: INTEGER);
PROCEDURE write (f: FILE; buf: ADDRESS; len: INTEGER);
PROCEDURE get (f: FILE; buf: ARRAY OF WORD; len: INTEGER);
PROCEDURE put (f: FILE; buf: ARRAY OF WORD; len: INTEGER);
------------------------------------------------------------
Операции обмена (передачи данных - data transfer) fread/fwrite, read/write, get/put осуществляют чтение/запись файлов.
Пары операций отличаются по протоколу вызова, но все они сводятся к двум базовым операциям fread/fwrite и в этом смысле почти им эквивалентны (см. примечание):
read (f,b,l) == fread (f,b,0,l)
write(f,b,l) == fwrite(f,b,0,l)
get(f,data,l) == fread (f,ADR(data),0,l)
put(f,data,l) == fwrite(f,ADR(data),0,l)
Операция fread для обычных файлов осуществляет чтение ранее записанных в файл данных. По окончании операции переменная iolen содержит число действительно прочитанных байтов. Это число может быть меньше, чем было заказано, если специальный файл открыт в режиме "без ожидания" (no wait) или встретился конец файла. Даже если в процессе чтения был достигнут конец файла, ошибка НЕТ ДАННЫХ не возбуждается! Если перед чтением указатель текущей позиции был строго (!) больше, чем eof, то при чтении ненулевого числа байтов возбуждается ошибка НЕТ ДАННЫХ.
Выполнение операции разрешено только в том случае, если программа обладает правом доступа к файлу по чтению.
Операция fwrite для обычных файлов осуществляет запись в файл данных. По окончании операции переменная iolen содержит число действительно записанных байтов.
Выполнение операции разрешено только в том случае, если программа обладает правом доступа к файлу по записи. В случае обычных (ordinary) файлов дополнительно требуется, чтобы носитель, на котором расположен файл, был смонтирован без запрещения записи (см. mount).
Если при записи указатель позиции в файле выходит за конец файла, файл автоматически увеличивается. Если файл должен быть увеличен на существенную длину (обычно несколько десятков килобайт), выгодно заранее (при создании) отвести соответствующее пространство файлу или расширить его перед записью операцией extend (см.).
Если в процессе записи и увеличения файла было исчерпано пространство на носителе, ошибка НЕТ СВОБОДНОГО МЕСТА (NO FREE SPACE) возбуждается только в том случае, когда ни одного байта информации записать не удалось. Если запись частично удалась (свободное место было исчерпано не в самом начале записи), ошибка не возбуждается, а переменная iolen содержит число действительно прочитанных байтов.
Если в процессе записи носителя на структурированном устройстве был достигнут конец устройства, ошибка НЕТ ДАННЫХ возбуждается только в том случае, когда ни одного байта информации записано не было. Если запись частично удалась (конец носителя был достигнут не в самом начале записи), ошибка не возбуждается, а переменная iolen содержит число действительно прочитанных байтов.
Выполнение операции разрешено только в том случае, если программа обладает правом доступа к файлу по записи.
Примечание. | Все операции, кроме fread/fwrite, дополнительно содержат проверку равенства числа переданных байтов (iolen) длине запроса на ввод/вывод len, и в случае несовпадения len и iolen при безошибочном выполнении fread/fwrite возбуждают ошибку НЕТ ДАННЫХ (NO DATA). |
После выполнения операции чтения/записи указатель текущей позиции в файле продвигается на iolen байтов. Если файл расширен при записи, указатель eof файла тоже увеличивается.
Операции записи в паре с операцией seek позволяют создать "дырявые" файлы, т.е. файлы, в которых записанная информация расположена не непрерывно. Такие файлы не противоречат концепциям, заложенным в файловую систему, и все операции над ними будут выполняться абсолютно корректно, если читается всегда только ранее записанная информация.
Примечание. | Полезно иметь в виду, что отведение места на носителе для хранения файла происходит порциями, кратными некоторому базовому размеру, обычно существенно большему, чем 1 байт (см. также операцию fstype). Поэтому при записи "кусочных" файлов могут появиться участки файла, информация в которые никогда не записывалась, но которые, тем не менее, можно прочитать. Значения, извлеченные из файла таким способом, с некоторой вероятностью (обычно маленькой) будут коррелировать с погодой на Марсе на момент извлечения. Разработчики не несут ответственность за неустойчивую наблюдаемость сей корреляции. |
Кроме того, что размер файла можно увеличить, дописывая в него информацию или принудительно выполняя операцию extend, размер файла можно также изменить, выполняя операции cut и end.
Операция end (см.) просто переставляет указатель конца файла (eof), не отводя дополнительного места на носителе (оно будет выделено при записи) при увеличении eof, и не утилизуя освободившегося пространства при уменьшении eof.
Следует иметь в виду, что файловая система поддерживает целостность файла только в диапазоне 0..eof-1, и в случае временного уменьшения eof и его последующего восстановления в прежнее значение целостность данных, оказавшихся на время переставления eof за пределами файла, не гарантируется! Они могут быть испорчены в результате выполнения коротких операций "дозаписи" за eof-ом, поскольку при таких "дозаписях", естественно, не производится "предчтение" записываемых блоков.
Операция cut (см.) аналогична операции end, но осуществляет утилизацию всего пространства, переставшего принадлежать файлу в результате его укорачивания. При последующем расширении файла пространство ему будут отводиться заново (и возможно, другое).
Возможно возникновение ошибок:
ЭТО ДИРЕКТОРИЯ is_dir
попытка записи в
файл, являющийся директорией;
НЕТ СВОБОДНОГО МЕСТА no_space
на носителе, где располагается
файл, нет свободного пространства, необходимого для увеличения его размера;
ПЛОХОЙ ДЕСКРИПТОР bad_desc
неоткрытый, или уже
закрытый, или испорченный file;
ЗАПРЕЩЕННЫЙ ДОСТУП ill_access
права доступа к файлу
не позволяют применить к нему данную операцию;
НЕТ ДАННЫХ no_data
попытка чтения из
файла данных, которых он не содержит по той или иной причине, или попытка
записать в файл данные, которые в него не влезают;
ПРЕРВАННАЯ ОПЕРАЦИЯ ipted_op
ОШИБКА ВВОДА/ВЫВОДА io_error **
ПЛОХАЯ ФАЙЛОВАЯ СИСТЕМА bad_fsys **
НЕ ОПРЕДЕЛЕНО undef **
8.7.16. doio
PROCEDURE doio(file: FILE; VAR r: defRequest.REQUEST);
------------------------------------------------------
Операция doio позволяет непосредственно обратиться к драйверу устройства.
Для выполнения операции doio необходимо, чтобы файл file был файлом-устройством, иначе возбуждается ошибка НЕПОДХОДЯЩИЙ (UNSUITABLE).
Для выполнении запроса с операцией READ из модуля defRequest требуется наличие права доступа к устройству по чтению. Для выполнении запроса с операцией WRITE из модуля defRequest требуется наличие права доступа к устройству по записи. Для выполнения любой другой операции необходимо наличие права доступа по исполнению.
Возможно возникновение ошибок:
ПЛОХОЙ ДЕСКРИПТОР bad_desc
неоткрытый, или уже
закрытый, или испорченный file;
НЕПОДХОДЯЩИЙ unsuitable
файл file не является устройством;
ЗАПРЕЩЕННЫЙ ДОСТУП ill_access
права доступа к файлу
не позволяют применить к нему данную операцию;
НЕТ ДАННЫХ no_data
попытка чтения из
файла данных, которых он не содержит, или попытка записать в файл данные,
которые в него не влезают;
НЕПРАВИЛЬНАЯ ОПЕРАЦИЯ ill_op
данная операция не применима
к этому файлу или не реализована в драйвере устройства;
ПРЕРВАННАЯ ОПЕРАЦИЯ ipted_op
ОШИБКА ВВОДА/ВЫВОДА io_error **
ПЛОХАЯ ФАЙЛОВАЯ СИСТЕМА bad_fsys **
НЕ ОПРЕДЕЛЕНО undef **
8.7.17. getch, putch, getstr, putstr, print
PROCEDURE getch(file: FILE; VAR ch: CHAR);
PROCEDURE putch(file: FILE; ch: CHAR);
PROCEDURE getstr(file: FILE; VAR str: ARRAY OF CHAR);
PROCEDURE putstr(file: FILE; str: ARRAY OF CHAR);
-----------------------------------------------------
Операции getch/putch и getstr/putstr осуществляют ввод/вывод для текстовых файлов.
Операции getch/putch читают(пишут) следующий байт из(в) файла точно так же, как это делают операции get(f,ch,1)/put(f,ch,1). Операции getch/putch могут с равным успехом применяться и к нетекстовым файлам.
Операция getstr читает из файла все байты до тех пор, пока не встретит байт с кодировкой 12c, или 15c, или 00c, или 36c ("разделитель"), или пока файл не будет исчерпан. getstr останавливается при возникновении любой из этих ситуаций (той, что случится раньше) и переписывает прочитанную информацию в строку str.
Если объем строки str оказался недостаточным для вмещения всей прочитанной информации, она усекается, и хвост этой информации теряется. Если чтение строки было остановлено по появлению разделителя, сам разделитель в файле пропускается, но в строку str не заносится. Строка str всегда завершается байтом с кодировкой 000c. Если размер строки <=0, то есть в нее нельзя положить даже байт 000c, возбуждается ошибка ПЛОХОЙ ПАРАМЕТР (BAD PARAMETER).
В переменную iolen всегда заносится длина реально прочитанной из файла информации (а не длина информации, занесенной в строку str), что позволяет определить (сравнивая iolen и BYTES(str)), произошла ли потеря информации из-за переполнения строки или нет.
Операция putstr записывает в файл все байты из строки str до тех пор, пока не встретит конец строки (байт с кодировкой 000c), или пока все содержимое строки str не будет записано.
Никакой разделитель строк в файл не записывается, тем самым последовательные вызовы putstr продолжают запись одной и той же строки. В случае необходимости записать в файл разделитель строк программа сама должна выполнить эту запись, предварительно приняв решение, какой разделитель строк использовать (см. примечание).
Следует иметь в виду, что при отсутствии буферизации побайтовый метод доступа к файлам может оказаться в десятки раз медленнее, чем обмен более крупными порциями (см. open).
Возможно возникновение ошибок:
ПЛОХОЙ ПАРАМЕТР bad_parm
строка str в операции getstr имеет размер BYTES(str)<=0;
ЭТО ДИРЕКТОРИЯ is_dir
попытка записи в
файл, являющийся директорией;
НЕТ СВОБОДНОГО МЕСТА no_space
на носителе, где располагается
файл, нет свободного пространства, необходимого для увеличения его размера;
ПЛОХОЙ ДЕСКРИПТОР bad_desc
неоткрытый, или уже
закрытый, или испорченный file;
ЗАПРЕЩЕННЫЙ ДОСТУП ill_access
права доступа к файлу
не позволяют применить к нему данную операцию;
НЕТ ДАННЫХ no_data
попытка чтения из
файла данных, которых он не содержит по той или иной причине, или попытка
записать в файл данные, которые в него не влезают;
ПРЕРВАННАЯ ОПЕРАЦИЯ ipted_op
ОШИБКА ВВОДА/ВЫВОДА io_error **
ПЛОХАЯ ФАЙЛОВАЯ СИСТЕМА bad_fsys **
НЕ ОПРЕДЕЛЕНО undef **
Примечание. |
Вопрос о разделителях строк в текстовых файлах достаточно запутан. Различные ОС и даже различные прикладные программы могут требовать различных разделителей строк в текстовых файлах. Внутренним стандартом для фирменных прикладных программ ОС Excelsior является чтение разделителей: LF (12c), CR LF (15c 12c), CR (15c), NUL (00c) и NL (36c). Запись производится с разделителем NL (36c). При чтении текстовых файлов, содержащих произвольные разделители из перечисленных, прикладной программе следует проявлять избыточный интеллект и после чтения каждой строчки, завершенной символом CR (15c), проверять, не является ли следующий символ символом LF (12с), и если это так, игнорировать (пропускать) его. Известные нам разделители:
(-) нет единого соглашения даже о записи файлов. |
PROCEDURE print(file: FILE; format: ARRAY OF CHAR; SEQ args: WORD);
--------------------------------------------------------------
Операция print осуществляет вывод в файл текстовой информации в соответствии с заданным форматом.
В ходе выполнения операции print запись информации в файл может происходить неоднократно, при этом iolen равно сумме длин запросов на вывод. В случае возникновения ошибок ввода/вывода done=FALSE, а error равно последней из возникших ошибок.
Заметим, что \n записывается как байт с кодом 36c, тогда как \r\l означают CR LF (см. выше). Подробности об операции print см. в разделе о стандартном вводе/выводе в Руководсте по ОС Excelsior.
8.7.18. cut, end, extend
PROCEDURE cut (file: FILE; size: INTEGER);
PROCEDURE end (file: FILE; size: INTEGER);
PROCEDURE extend(file: FILE; size: INTEGER);
--------------------------------------------
Операции extend, cut, end обеспечивают возможность управления размером файла и размером отведенного для него пространства на носителе.
Операция extend отводит файлу пространство на носителе, необходимое для размещения в нем size байтов. После успешного выполнения операции extend указатель конца файла не изменяется, но в файле теперь достаточно пространства для хранения в нем size байтов, все последующие операции записи в границах 0..size-1 не потребуют отведения места на носителе. При расширении "дырявого" файла для всех "дырок", имевшихся в файле, отводится пространство на носителе. При возникновении ошибок (кроме помеченных **) в исполнении операции extend пространство, отведенное файлу, и сам файл остаются без изменений.
Операция end переставляет указатель конца файла, не отводя нового места на носителе (в случае увеличения eof) и не утилизуя освободившееся место (в случае уменьшения).
Операция cut переставляет указатель конца файла и утилизует освобождаемое пространство между новым и старым значениями eof.
Выполнение этих операций разрешено только для обычных (ordinary) файлов, не являющихся директориями и только в том случае, если программа обладает правом доступа к файлу по записи и носитель, на котором расположен файл, смонтирован без запрещения записи (см. mount).
Возможно возникновение ошибок:
ПЛОХОЙ ПАРАМЕТР bad_parm
указанный параметр size меньше нуля или слишком велик для носителя, на котором
расположен файл;
ЭТО ДИРЕКТОРИЯ is_dir
файл является
директорией;
НЕТ СВОБОДНОГО МЕСТА no_space
на носителе, где располагается
файл, нет свободного пространства, необходимого для увеличения его размера;
ПЛОХОЙ ДЕСКРИПТОР bad_desc
неоткрытый, или уже
закрытый, или испорченный file;
ЗАПРЕЩЕННЫЙ ДОСТУП ill_access
права доступа к файлу
не позволяют применить к нему данную операцию;
ЗАЩИТА ЗАПИСИ write_pro
носитель, на
котором открыт файл, смонтирован "только для чтения" или защищен от записи
аппаратным способом (например, выключателем на устройстве или заклеиванием соответсвующего
отверстия на гибком диске и т.п.);
ПРЕРВАННАЯ ОПЕРАЦИЯ ipted_op
ОШИБКА ВВОДА/ВЫВОДА io_error **
ПЛОХАЯ ФАЙЛОВАЯ СИСТЕМА bad_fsys **
НЕ ОПРЕДЕЛЕНО undef **
8.7.19. fstype
PROCEDURE fstype(file: FILE; VAR type,blocksize: INTEGER);
----------------------------------------------------------
Операция fstype позволяет узнать тип файловой системы, в которой расположен открытый файл file, а также размер блока, используемого для отведения и утилизации пространства на носителе и организации доступа к файлам.
Операция fstype может быть применена только к обычным (ordinary) файлам и директориям. При попытке применить ее к специальным файлам произойдет возбуждение ошибки НЕПОДХОДЯЩИЙ (UNSUITABLE).
Возможно возникновение ошибок:
ПЛОХОЙ ДЕСКРИПТОР bad_desc
неоткрытый, или уже
закрытый, или испорченный file;
НЕПОДХОДЯЩИЙ unsuitable
ПЛОХАЯ ФАЙЛОВАЯ СИСТЕМА bad_fsys **
НЕ ОПРЕДЕЛЕНО undef **
8.7.20. flush
PROCEDURE flush (file: FILE);
-----------------------------
Операция flush обеспечивает проведение мер по обеспечению когеррентности информации файла в памяти и его образа на диске.
При выполнении операции flush на диск заносятся все его изменившиеся атрибуты, ожидаются окончания всех задержанных записей и производится запись всех изменившихся буферов файла.
Операция flush не эквивалентна закрытию файла и последующему его открытию, т.к. права доступа программы к файлу сохраняются неизменными при ее выполнении, но могут измениться при закрытии и последующем открытии файла (не говоря уже про то, что временный файл вообще нельзя открыть после закрытия).
Если при выполнении операции flush не обнаружено изменившихся атрибутов, задержанных записей и изменившихся буферов, операция игнорируется.
Возможно возникновение ошибок:
НЕТ СВОБОДНОГО МЕСТА no_space
на носителе, где располагается
файл, нет свободного пространства, необходимого для увеличения его размера (вызванного
записью изменившихся буферов);
ПЛОХОЙ ДЕСКРИПТОР bad_desc
неоткрытый, или уже
закрытый, или испорченный file;
ЗАПРЕЩЕННЫЙ ДОСТУП ill_access
права доступа к файлу
не позволяют применить к нему данную операцию;
ПРЕРВАННАЯ ОПЕРАЦИЯ ipted_op
ОШИБКА ВВОДА/ВЫВОДА io_error **
ПЛОХАЯ ФАЙЛОВАЯ СИСТЕМА bad_fsys **
НЕ ОПРЕДЕЛЕНО undef **
8.7.21. mkfs
PROCEDURE mkfs (device: FILE; fstype: INTEGER; blocksize: INTEGER; label: ARRAY OF CHAR; bads: ARRAY OF INTEGER);
-------------------------------------------
Операция mkfs инициализирует носитель, установленный на структурированном устройстве dev, и создает на нем новую файловую систему.
Для выполнения операции mkfs нужно иметь права доступа к файлу-устройству по чтению и записи.
Массив bads содержит номера "плохих" блоков на носителе. Файловая система не будет использовать эти блоки в своей работе и включит их в файл "BAD.BLOCKS".
Строка label несет чисто информациолнный смысл, она будет возвращаться в операциях fmount/mount.
Файловая система, созданная операцией mkfs, состоит из корневой директории носителя и следующих двух или трех входов на ней:
".." | ссылка на саму корневую директорию; |
"SYSTEM.BOOT" | пустой файл, предназначенный для хранения bootstrap'ного образа системы; |
"BAD.BLOCKS" | файл, "закрывающий" плохие блоки на носителе (только если bads>0). |
Возможно возникновение ошибок:
ПЛОХОЙ ДЕСКРИПТОР bad_desc
неоткрытый, или уже
закрытый, или испорченный файл dev;
ПЛОХОЙ ПАРАМЕТР bad_parm
bads>HIGH(badb)+1
ЗАНЯТО busy
носитель на устройстве
уже подмонтирован к файловому дереву или открыт другой задачей;
ЗАПРЕЩЕННЫЙ ДОСТУП ill_access
права доступа к файлу
не позволяют применить к нему данную операцию;
ЗАЩИТА ЗАПИСИ write_pro
носитель, смонтированный
на устройстве dev, защищен от записи аппаратным способом (например,
выключателем на устройстве или заклеиванием соответсвующего отверстия на гибком
диске и т.п.);
НЕПОДХОДЯЩИЙ unsuitable
файл dev не является структурированным устройством;
НЕТ СВОБОДНОГО МЕСТА no_space
носитель слишком маленький
или в списке "плохих" блоков обнаружен один из тех, что необходимы
для нормального устройства файловой системы;
ПРЕРВАННАЯ ОПЕРАЦИЯ ipted_op
ОШИБКА ВВОДА/ВЫВОДА io_error **
ПЛОХАЯ ФАЙЛОВАЯ СИСТЕМА bad_fsys **
НЕ ОПРЕДЕЛЕНО undef **
8.7.22. mount, fmount, unmount, funmount
PROCEDURE mount (path,dev,info: ARRAY OF CHAR; VAR label: ARRAY OF CHAR; ro: BOOLEAN);
PROCEDURE fmount (cd: FILE; path,dev,info: ARRAY OF CHAR; VAR label: ARRAY OF CHAR; ro: BOOLEAN);
-------------------------------------------------------------
PROCEDURE unmount (path: ARRAY OF CHAR; method: INTEGER);
PROCEDURE funmount (cd: FILE; path: ARRAY OF CHAR; method: INTEGER);
---------------------------------------------------------
Операции mount, fmount предназначены для подмонтирования к файловому дереву поддеревьев, расположенных на носителях, установленных на структурированных устройствах (для краткости - "монтирование устройства").
Операции unmount, funmount демонтируют с файлового дерева ранее подмонтированные к нему поддеревья.
Операции mount, unmount являются точными эквивалентами операций fmount(BIO.cd,.....), funmount(BIO.cd,.....).
Монтирование устройства возможно в любое место файлового дерева. Для монтирования устройства необходимо существование директории, на которую данное устройство будет смонтировано.
Маршрут, ведущий к директории, на которую будет смонтировано устройство, задается параметром path, файл устройства, на котором будет монтироваться носитель, задается параметром dev. Параметр info передается драйверу в момент монтирования в качестве параметра запроса MOUNT и может содержать специфическую информацию, полезную (или даже необходимую) драйверу для осуществления правильной работы с устройством. В переменной label возвращается "метка тома", которая носит чисто информационный (символический) характер и никак не влияет на работу файловой системы.
При монтировании устройства имеется возможность запретить любые модификации информации, расположенной на устройстве, независимо от индивидуальных прав доступа к каждому конкретному файлу или директории. Для этого необходимо передать операции монтирования read_only-параметр (ro), равный TRUE. Следует обратить внимание, что такое запрещение записи сродни физической защите носителя (или устройства от записи) и не сказывается на возможности программ открывать на этом устройстве файлы с требованием прав записи в операции open. Такие права будут предоставляться вне зависимости от режима, в котором смонтировано устройство (что обеспечит возможность частичной работоспособности многих программ), но при попытке модифицировать информацию на носителе, смонтированном с параметром read_only, будет возникать ошибка ЗАЩИТА ЗАПИСИ (WRITE PROTECT), и информация модифицироваться не будет. Заметьте, что ошибка ЗАЩИТА ЗАПИСИ будет возникать в момент применения операции, изменяющей информацию на носителе, в противовес ошибке НАРУШЕНИЕ СЕКРЕТНОСТИ, происходящей в момент открытия файла.
Поскольку ссылка на устройство также хранится в файловом дереве (см. mknode) и снабжена набором прав доступа, очевидно, что для подмонтировании носителя на устройстве с требованием возможности записи на него необходимо иметь право записи на это устройство и на директорию, на которую будет произведено подмонтирование, в противном случае возникнет ошибка НАРУШЕНИЕ СЕКРЕТНОСТИ в момент подмонтирования.
После успешного подмонтирования файлового поддерева на директорию во всех маршрутах, проходящих через эту директорию, она будет ассоциироваться с корневой директорией подмонтированного носителя. Вход ".." на этой директории, тем не менее, сохранит свое нормальное значение. Прежнее содержимое директории (если таковое имеется) станет недоступным вплоть до момента демонтирования.
Процесс монтирования не сопряжен с необходимостью записи информации на носитель, к которому идет подмонтирование, что обеспечивает возможность протягивать цепочки смонтированных поддеревьев даже через смонтированные с параметром read_only носители. Никаких следов подмонтирования и демонтирования на носителе не остается.
Устройство не может быть смонтировано больше одного раза, и не может быть подмонтировано больше одного устройства на один узел файлового дерева. Этим гарантируется "деревянность" дерева, то есть отсутствие в нем циклов.
Операция демонтирования позволяет отмонтировать файловое поддерево от директории. Для успешного демонтирования необходимо указать директорию, на которую ранее было произведено монтирование, и метод обработки "плохих" файлов. В случае успешного демонтирования устройства директория восстанавливает свои нормальные, обычные свойства. Если указанная директория не является местом монтирования, возбуждается ошибка НЕ ОПРЕДЕЛЕНО (UNDEFUNED).
Для успешного демонтирования носителя все файлы на нем должны быть закрыты, иначе возникает ошибка ЗАНЯТО (BUSY), и демонтирование не выполняется. Причины наличия на устройстве незакрытых файлов могут быть следующие. Первая: наличие активных или остановленных задач, открывших или создавших файлы на этом носителе. Вторая - наличие "плохих" файлов. Первая причина не требует дополнительных средств для борьбы со своими последствиями.
"Плохие" файлы на носителе могут образовываться в результате невозможности (из-за аппаратной ошибки, например) записать на носитель изменившиеся атрибуты файлов или других внутренних структур данных. В этой ситуации задача, осуществлявшая операции закрытия (close или purge) или утрамбовывания (flush) соответствующего файла, получает извещение о случившейся ошибке, но файл остается незакрытым и помечается как "плохой". При демонтировании носителя, на котором остались "плохие" файлы, играет роль значение параметра method. Существует три метода демонтирования таких носителей.
1) method=0. Делается попытка демонтирования носителя, и если на нем есть незакрытые или "плохие" файлы, возбуждается ошибка ЗАНЯТО (BUSY), и носитель не демонтируется.
2) method=1. Делается попытка демонтирования носителя, и если на нем етсь "плохие" файлы, все "плохие" файлы игнорируются, возбуждается ошибка ЗАНЯТО (BUSY), но носитель демонтируется!
3) method=2. Делается попытка демонтирования носителя, и если на нем есть "плохие" файлы, все "плохие" файлы игнорируются, ошибка ЗАНЯТО не возбуждается, и носитель демонтируется. Если при указании метода 2 все равно возбуждается ошибка ЗАНЯТО, это свидетельствует о том, что в системе в данный момент существуют задачи, имеющие открытые на этом носителе файлы. Необходимо либо дождаться их завершения, либо принудительно завершить их.
Возможно возникновение ошибок:
ЭТО НЕ ДИРЕКТОРИЯ not_dir
имя в префиксе
маршрута указывает не на директорию, или значение cd
не является директорией;
ПЛОХОЙ ДЕСКРИПТОР bad_desc
плохое значение
параметра или переменной cd;
НЕТ ТАКОГО no_entry
на директории, указываемой
маршрутом, не найден файл с указанным именем, или не найдена директория для
одного из имен в префиксе маршрута, или не найдено устройство;
ЗАНЯТО busy
носитель на устройстве
подмонтирован к файловому дереву или открыт другой задачей;
ЗАПРЕЩЕННЫЙ ДОСТУП ill_access
права доступа к файлу
не позволяют применить к нему данную операцию;
ЗАЩИТА ЗАПИСИ write_pro
носитель на устройстве
dev защищен от записи аппаратным способом (например,
выключателем на устройстве или заклеиванием соответсвующего отверстия на гибком
диске и т.п.);
НЕПОДХОДЯЩИЙ unsuitable
файл dev не является структурированным устройством;
НЕ ОПРЕДЕЛЕНО undef
попытка демонтирования
от директории, на которую ничего не смонтировано;
НЕТ ПАМЯТИ no_memory
НАРУШЕНИЕ СЕКРЕТНОСТИ sec_vio
ПЛОХОЕ ИМЯ bad_name
ПРЕРВАННАЯ ОПЕРАЦИЯ ipted_op
ПЛОХАЯ ФАЙЛОВАЯ СИСТЕМА bad_fsys **
ОШИБКА ВВОДА/ВЫВОДА io_error **
НЕ ОПРЕДЕЛЕНО undef **
8.7.23. mknode, fmknode
PROCEDURE mknode ( path,name: ARRAY OF CHAR);
PROCEDURE fmknode(cd: FILE; path,name: ARRAY OF CHAR);
------------------------------------------------------
Операции mknode, fmknode позволяют создать ссылающийся на устройство узел в файловом дереве.
Операция mknode является точными эквивалентом операции fmknode(BIO.cd,.....).
Операция mknode создает специальный узел в файловой системе на директории, указываемой префиксом маршрута path, и с именем из маршрута path, ссылающийся на устройство с именем name. Все последующие открытия этого узла будут приводить к открытию устройства с именем name. При создании узла необязательно и не проверяется наличие драйвера устройства с именем name. При создании и привязывании узла ему устанавливаются права доступа из переменной cmask.
Следует иметь в виду, что операции chaccess и chowner не смогут изменить права доступа и хозяина узла, созданного операцией mknode. Они будут изменять только права доступа и хозяина самого открытого устройства, но при закрытии файла устройства эти изменения не будут сохранены в соответствующем узле.
Изменения прав доступа к устройству можно добиться, уничтожив узел и создав вместо него новый с другими правами доступа.
Уничтожение узла, созданного операцией mknode, может быть произведено обычной операцией unlink.
Возможно возникновение ошибок:
ЭТО НЕ ДИРЕКТОРИЯ not_dir
имя в префиксе
маршрута указывает не на директорию, или значение cd
не является директорией;
НОСИТЕЛЬ ПЕРЕПОЛНЕН fsys_full
на носителе, где создается
узел, переполнена таблица файлов;
НЕТ СВОБОДНОГО МЕСТА no_space
на носителе, где создается
узел, нет свободного пространства, необходимого для увеличения размера директории;
НЕТ ТАКОГО no_entry
не найдена директория
для одного из имен в префиксе маршрута;
ПЛОХОЙ ДЕСКРИПТОР bad_desc
плохое значение
параметра или переменной cd;
НАРУШЕНИЕ СЕКРЕТНОСТИ sec_vio
нет права записи в директорию,
к которой ведется привязывание;
ПЛОХОЕ ИМЯ bad_name
неправильное имя в
указанном маршруте, или неправильное имя устройства;
ПРЕРВАННАЯ ОПЕРАЦИЯ ipted_op
ОШИБКА ВВОДА/ВЫВОДА io_error **
ПЛОХАЯ ФАЙЛОВАЯ СИСТЕМА bad_fsys **
НЕ ОПРЕДЕЛЕНО undef **
8.7.24. kind
PROCEDURE kind(file: FILE): BITSET;
-----------------------------------
CONST is_dir is_tty is_disk is_spec is_hidd is_sys
Операция kind позволяет определить вид файла. В случае применения к BIO.null, неоткрытому или уже закрытому файлу возбуждается ошибка ПЛОХОЙ ДЕСКРИПТОР и возвращается {}.
Файл-устройство может быть определен так:
kind(file) * (is_tty+is_disk+is_spec) # {}
Вид is_hidd может комбинироваться с другими видами файлов и означает, что при открытии файла в соответствующем входе в директорию был выставлен признак hidden (скрытый), или файл был создан с параметром mode, содержащим 'h'.
Возможно возникновение ошибок:
ПЛОХОЙ ДЕСКРИПТОР bad_desc
плохое значение параметра file.
8.7.25. chmode
PROCEDURE chmode(file: FILE; mode: ARRAY OF CHAR);
--------------------------------------------------
Изменяет способы доступа, с которыми файл был открыт или создан. Параметр mode такой же, как в операции open. В случае невозможности сменить способ доступа к файлу возбуждается ошибка НАРУШЕНИЕ СЕКРЕТНОСТИ.
Синтаксис строки mode такой же, как у операций create и open (см.).
В случае возникновение ошибки НАРУШЕНИЕ СЕКРЕТНОСТИ (SECURITY VIOLATION) метод доступа к файлу не изменяется.
Возможно возникновение ошибок:
ПЛОХОЙ ДЕСКРИПТОР bad_desc
плохое значение
параметра file;
НАРУШЕНИЕ СЕКРЕТНОСТИ sec_vio
8.7.26. chcmask, access, owner
CONST (* protection bits *)
own_exec gro_exec oth_exec
own_write gro_write oth_write
own_read gro_read oth_read
own_search gro_search oth_search
run_uid run_priv unlink_pro
PROCEDURE chcmask (mask: BITSET);
--------------------------------
PROCEDURE access (file: FILE): BITSET;
-------------------------------------
PROCEDURE owner (file: FILE; VAR uid,uid: INTEGER);
--------------------------------------------------
Операция chcmask позволяет установить маску защиты, которая будет приписываться всем создаваемым с помощью create, mkdir и mknode файлам.
Операция access позволяет узнать маску защиты открытого или созданного файла.
Операция owner позволяет узнать uid и gid влядельца открытого или созданного файла.
Следует иметь в виду следующее: (xxx = own, gro, oth).
Признаки защиты xxx_exec и xxx_search - это один и тот же признак, отличающийся только интерпретацией для директорий, обычных файлов и файлов-устройств.
Признаки xxx_read, xxx_write, xxx_search, (xxx_exec), будучи выставленными, запрещают (!) соответствующий метод доступа.
Признак unlink_pro, будучи выставлен, запрещает отвязывать (unlink) файл до тех пор, пока этот признак не уберут (см. chaccess).
Признаки run_priv, run_uid действуют только для исполняемых файлов и означают, что при исполнении файла должен быть выставлен привилегированный режим или должен быть выставлен идентификатор группы (group id) и пользователя (user id) соответственно.
Выставление в cmask признаков run_priv, run_uid разрешено только в привилегированном режиме.
В переменной cmask всегда содержатся признаки защиты для создаваемых файлов. Переменная инициализируется в момент запуска задачи путем сканирования строки из ОКРУЖЕНИЯ (Environment) по имени "CMASK". При отсутствии такой строки или в случае ошибки в ее синтаксисе cmask инициализируется значением по умолчанию:
cmask = oth_write+oth_read+oth_exec+gro_write
, то есть в создаваемые файлы запись запрещена для всех, кроме владельца (owner), чтение и исполнение (или просмотр) разрешено только для владельца и членов его группы.
Возможно возникновение ошибок:
ПЛОХОЙ ДЕСКРИПТОР bad_desc
плохое значение
параметра file в операции access;
ДЛЯ ПРИВИЛЕГИРОВАННЫХ su_only
попытка выставить в
cmask признаки run_priv, run_uid в непривилегированном режиме. При
возникновении этой ошибки признаки run_priv, run_uid игнорируются, остальные признаки выставляются
в cmask;
8.7.27. chaccess, chowner
PROCEDURE chaccess(file: FILE; mask: BITSET);
PROCEDURE chowner (file: FILE; owner,group: INTEGER);
-----------------------------------------------------
Операции chaccess, chowner позволяют изменить маску защиты файла и его владельца соответственно.
Для изменения признаков защиты и смены владельца необходимо быть владельцем файла или находиться в привилегированном режиме.
Описание признаков защиты см. в описании chcmask.
После смены владельца (owner) у файла вернуть файл прежнему владельцу может только новый владелец или привилегированный пользователь.
При изменении владельца файла или признаков защиты права доступа к данному файлу программы, которая произвела эти изменения, остаются прежними вплоть до закрытия файла.
Например, программа, являющаяся владельцем файла, имеет право доступа по записи к нему и выставила признак запрета записи для владельца. Несмотря на это, право записи в этот файл останется для нее прежним (т.е. она сможет продолжать записывать данные в файл) вплоть до закрытия файла. При повторном (с момента смены признаков защиты) открытии файла этой программой или любой другой с требованием права записи открытие будет отклонено из-за ошибки НАРУШЕНИЕ СЕКРЕТНОСТИ.
Возможно возникновение ошибок:
ПЛОХОЙ ДЕСКРИПТОР bad_desc
плохое значение
параметра file;
ДЛЯ ПРИВИЛЕГИРОВАННЫХ su_only
попытка выставить признаки
run_priv, run_uid в непривилегированном режиме. При возникновении этой ошибки признаки
run_priv, run_uid игнорируются, остальные признаки выставляются;
НАРУШЕНИЕ СЕКРЕТНОСТИ sec_vio
попытка изменить
признаки или владельца у "чужого" файла (у файла, владельцем которого
программа не является).
8.7.28. get_attr, set_attr
PROCEDURE get_attr(file: FILE; no: INTEGER; VAR val: WORD);
PROCEDURE set_attr(file: FILE; no: INTEGER; val: WORD);
------------------------------------------------------------
CONST a_links a_inode a_ctime a_wtime a_gid a_uid a_pro
Операции get_attr, set_attr позволяют прочитать и записать некоторые полезные атрибуты файла, не доступные иным путем.
Прочитать любой атрибут имеет право любая программа у любого файла (в любое время, и вне зависимости от местоположения компутера, Земли, Луны, Солнца и созвездия Аль Забих и др. небесных тел).
Изменять атрибуты операцией set_attr имеют право:
a_links | только привилегированные; |
a_inode | только привилегированные; |
a_ctime | только владелец или привилегированные; |
a_wtime | только владелец или привилегированные; |
a_gid | никто; |
a_uid | никто; |
a_pro | никто. |
Атрибуты a_gid, a_uid, a_pro изменяются операциями chaccess, chowner, поэтому изменение их операцией set_attr запрещено.
Возможно возникновение ошибок:
ПЛОХОЙ ДЕСКРИПТОР bad_desc
плохое значение
параметра file;
ПЛОХОЙ ПАРАМЕТР bad_parm
попытка изменить a_gid, a_uid,
a_pro в set_attr;
ДЛЯ ПРИВИЛЕГИРОВАННЫХ su_only
попытка изменить a_links, a_inode в непривилегированном режиме;
НАРУШЕНИЕ СЕКРЕТНОСТИ sec_vio
попытка изменить a_ctime, a_wtime "чужого" файла (файла, владельцем
которого программа не является).
8.7.29. dir_walk, end_walk, restart_walk
CONST sort_none sort_reverse
sort_name sort_ext
sort_time sort_cre
sort_eof sort_dirfwd
PROCEDURE dir_walk (cd: FILE; sort: INTEGER);
PROCEDURE end_walk (cd: FILE);
--------------------------------------------
PROCEDURE restart_walk (cd: FILE);
---------------------------------
Операция dir_walk начинает итерацию (прогулку по) директории. Операция end_walk завершает итерацию директории. Операция restart_walk позволяет начать итерацию директории заново.
Для итерации директории программа должна обладать правом доступа к данной директории по просмотру, т.е. при открытии директории, которую программа собирается итерировать, следует указать флаг 'x' или 'X' в параметре mode (см. open).
Директория BIO.cd всегда открывается (если вообще открывается) с максимально допустимыми правами доступа ('X' в mode).
В момент начала итерации директории ее содержимое читается в память и, возможно, сортируется. Поэтому на протяжении итерации директории могут возникнуть две следующие ситуации:
1) за время итерации к директории привязали файл, в результате чего возник вход с новым именем, который не будет проитерирован.
2) за время итерации от директории отвязали файл, в результате чего исчез вход, который тем не менее будет проитерирован. В связи с этим не следует считать фатальной ошибку НЕТ ТАКОГО (NO ENTRY) при выполнении операции get_entry.
Параметр sort может быть образован как сумма (*):
none | не сортировать; |
reverse | сортировка в обратном порядке; |
name | сортировка по именам; |
ext | сортировать по расширителям (**); |
time | сортировка по времени; |
cre | сортировка по времени создания (а не записи); |
eof | сортировка по размерам; |
dirfwd | директории перед файлами (иначе вперемежку). |
*) в версиях системы до 1.3 реализована только сортировка sort_none.
**) для файлов с одинаковым расширителем может быть произведена, если требуется, сортировка по именам, по временам или по размерам.
При попытке повторно применить операцию dir_walk к одной и той же директории возникнет ошибка ЗАНЯТО (BUSY). Это вовсе не означает, что директория не может одновременно итерироваться несколькими программами. Смысл этой ошибки состоит в том, что одна и та же программа пробует одновременно прогуляться по одной и той же директории. Причина запрета таких множественных прогулок очевидна - неизвестно, кто и где гуляет (да и сортировки могут быть разные).
Операция restart_walk позволяет начать итерацию директории с начала. Restart_walk не производит чтения и сортировки директории, а только переставляет на начало указатель текущего входа итерации директории. Очевидно, что restart_walk можно выполнять только после dir_walk и до end_walk.
Следует иметь в виду, что end_walk завершает итерацию директории и освобождает всю занятую память, но не закрывает самой директории, которая (в случае необходимости) должна быть закрыта операцией close.
Будьте внимательны, не закройте случайно BIO.cd!
Возможно возникновение ошибок:
ЭТО НЕ ДИРЕКТОРИЯ not_dir
значение cd не является директорией;
ПЛОХОЙ ДЕСКРИПТОР bad_desc
плохое значение
параметра cd;
ПЛОХОЙ ПАРАМЕТР bad_parm
неправильное
значение параметра sort;
НЕПОДХОДЯЩИЙ unsuitable
попытка закончить или
рестартовать итерацию директории, для которой не выполнялось dir_walk;
ЗАНЯТО busy
НЕТ ПАМЯТИ no_memory
ЗАПРЕЩЕННЫЙ ДОСТУП ill_access
ПРЕРВАННАЯ ОПЕРАЦИЯ ipted_op
ПЛОХАЯ ФАЙЛОВАЯ СИСТЕМА bad_fsys **
ОШИБКА ВВОДА/ВЫВОДА io_error **
НЕ ОПРЕДЕЛЕНО undef **
8.7.30. get_entry
CONST e_dir e_hidden e_esc e_sys
PROCEDURE get_entry(cd: FILE; VAR name: ARRAY OF CHAR; VAR mode: BITSET): BOOLEAN;
---------------------------------------------------------
Операция get_entry выдает информацию об очередном (если имеется) входе итерируемой директории или сигнализирует об окончании итерации.
Операция get_entry возвращает значение TRUE, если удалось получить информацию об очередном входе.
Операция get_entry возвращает значение FALSE, если на итерируемой директории больше нет входов или get_entry применяется к недиректории или к директории, к которой не применялся dir_walk (см.).
В параметре name возвращается имя входа, в параметре mode - признаки входа. Такими признаками могут быть
e_dir | вход ссылается на директорию; |
e_esc | вход ссылается на узел-устройство; |
e_hidden | имя во входе считается "скрытым"; |
e_sys | вход ссылается на системный-файл, |
а также их разумные комбинации.
Последние два признака (hidden, sys) имеют чисто утилитарный характер, то есть используются только утилитами для принятия решения о включении или невключении файла во множество файлов, над которыми выполняются операции.
Возможно возникновение ошибок:
ЭТО НЕ ДИРЕКТОРИЯ not_dir
значение cd не является директорией;
ПЛОХОЙ ДЕСКРИПТОР bad_desc
плохое значение
параметра cd;
НЕПОДХОДЯЩИЙ unsuitable
попытка закончить или
рестартовать итерацию директории, для которой не выполнялось dir_walk;
При любой из ошибок get_entry возвращает FALSE.
8.7.31. open_paths, close_paths, get_paths
TYPE PATHs;
-----------
VAL here: PATHs; empty: PATHs;
-------------------------------
Значениями типа PATHs являются упорядоченные множества директорий, на которых будет производиться поиск операцией lookup (см.). Имеются два предопределенных значения типа PATHs.
Значение empty суть предопределенное неопределенное значение типа PATHs. Значение here построено операцией
open_paths(here,".")
и может быть использовано вместо любого иного значения в качестве умолчания или при неудачном открытии требуемых путей. Значение here в качестве множества директорий, относительно которых будет интерпретироваться маршрут, содержит только текущую директорию, и поэтому:
lookup(here,file,name,mode)
абсолютно эквивалентно
open(file,name,mode).
PROCEDURE open_paths (VAR dirs: PATHs; paths: ARRAY OF CHAR);
PROCEDURE get_paths (VAR dirs: PATHs; envnm: ARRAY OF CHAR);
PROCEDURE close_paths(VAR dirs: PATHs);
-------------------------------------------------------------
Операции open_paths, get_paths, close_paths позволяют создавать новые значение типа PATHs по спецификации, заданной строкой paths (open_paths), по спецификации, извлеченной из ОКРУЖЕНИЯ (Environment), по имени envnm (get_paths), а также уничтожать значения типа PATHs (close_paths).
Синтаксис спецификации множества путей поиска файлов следующий:
paths = маршрут { пробелы маршрут } 000c .
пробелы = " " { " " } .
В случае неправильного задания спецификации в операциях open_paths, get_paths можут возникнуть ошибки ПЛОХОЕ ИМЯ (BAD NAME) или ПЛОХОЙ ПАРАМЕТР (BAD PARAMETER). Если в ОКРУЖЕНИИ не найдено имя envnm, заданное в get_paths, возбуждается ошибка НЕТ ТАКОГО (NO ENTRY).
Порядок поиска (и вообще Порядок) в порожденном значении типа PATHs соответствует порядку перечисления маршрутов в спецификации.
Операция close_paths закрывает все директории, составляющие множество путей (если они были открыты), и уничтожает значение типа PATHs.
Возможно возникновение ошибок:
ПЛОХОЙ ПАРАМЕТР bad_parm
ПЛОХОЕ ИМЯ bad_name
НЕТ ПАМЯТИ no_memory
8.7.32. lookup
PROCEDURE lookup (dirs: PATHs; VAR file: FILE; name,mode: ARRAY OF CHAR);
-------------------------------------------------------------
Операция lookup осуществляет поиск и открытие файла, интерпретируя маршрут к файлу относительно всех директорий из множества dirs. В случае успешного поиска открытие файла происходит в точности так же, как в операции open (см.).
Следует иметь в виду следующие важные особенности операции lookup и значения типа PATHs.
Если операции lookup указывается абсолютный маршрут к файлу (начинается от корня), поиска на директориях dirs не происходит.
После выполнения операции open_paths директории из множества, определяющего места поиска, остаются неоткрытми (!) и будут открываться лишь по мере необходимости. После открытия директории из множества dirs она остается открытой вплоть до выполнения операции close_paths.
Директория, указанная в спецификации как ".", напротив, никогда (!) не открывается, вместо нее всегда используется значение переменной BIO.null.
Эти два свойства необходимо учитывать при задании спецификации, так как можно получить достаточно неожиданные эффекты, комбинируя вызовы open_paths, chdir, lookup. Поэтому рекомендуется избегать задания в спецификации относительных маршрутов (кроме "."), поскольку их интерпретация может существенно меняться при смене директории, а apriory неизвестно, на какой директории произойдет действительное открытие каждого из элементов множества dirs.
Следует также иметь в виду, что если операции lookup не удается открыть один из элементов (упорядоченного) множества путей по причинам НЕТ ТАКОГО (NO ENTRY) или НАРУШЕНИЕ СЕКРЕТНОСТИ (SECURITY VIOLATION), lookup игнорирует эту ошибку (но не какую-либо другую), откладывая открывание этого элемента до лучших времен, и переходит к попытке открытия следующего элемента множества.
Возможно возникновение ошибок:
НЕТ ТАКОГО no_entry
файл не найден
относительно ни одной из директорий;
ПЛОХОЙ ДЕСКРИПТОР bad_desc
плохое значение
параметра dirs;
ЭТО НЕ ДИРЕКТОРИЯ not_dir
в значении dirs один
из маршрутов указывает не на директорию,
а также любой из ошибок операции open (см.).
8.7.33. lock, unlock
PROCEDURE lock (time_out: INTEGER; file: FILE);
PROCEDURE unlock (file: FILE);
------------------------------------------------
Операции lock и unlock позволяют двум или более программам (да и процессам тоже!) синхронизовать свои операции над файлами.
Операция lock осуществляет попытку захвата файла. Захват файла может быть удачным или неудачным, что легко проверить, тестируя done и error.
В случае задания time_out<0 (-1, например) попытка захватить уже захваченный другим процессом (возможно, другой программы) файл затянется до тех пор, пока захватившая файл программа не отпустит его, или не завершится, или не будет остановлена, программа пытающаяся выполнить этот lock.
В случае задания time_out=0 производится попытка немедленного захвата файла, и если это не удалось, возбуждается ошибка ЗАНЯТО (BUSY).
В случае указания time_out>0 производится попытка захвата файла, и если это не удалось, производится ожидание момента, когда захватившая файл программа отпустит его, или завершится, или будет остановлена программа, пытающаяся выполнить эту операцию lock, или будет исчерпано время (в милисекундах) time_out. В последнем случае будет возбуждена ошибка ВРЕМЯ ВЫШЛО (TIME OUT).
Операция unlock производит немедленное освобождение ранее захваченного файла. Если при этом другие процессы находятся в ожидании захвата файла, первый из них будет продолжен с удачным захватом файла.
Захват файла операцией lock действует только на выполнение операции lock над тем же файлом, но не на другие операции с ним. Таким образом, lock/unlock могут служить синхронизирующими примитивами только для процессов, разработанных с учетом возможности одновременной работы с файлами, но не для произвольных процессов.
Захват и освобождение файла необходимо только для процессов, желающих выполнить последовательность операций над файлом во взаимоисключающем режиме. Взаимное исключение задач и процессов при выполнении атомарных операций обеспечивается самой файловой системой.
Все захваченные (и не освобожденные) процессом файлы будут освобождены в случае аварийного (или нормального) завершения процесса.
Следует иметь в виду, что в версиях системы до 1.3 при закрытии захваченного файла (close) не производится его автоматическое освобождение. Тем самым, программа, закрывшая захваченный ею файл, теряет возможность его освободить вплоть до своего завершения. Будьте осторожны!
Возможно возникновение ошибок:
ПЛОХОЙ ДЕСКРИПТОР bad_desc
плохое значение
параметра file;
ВРЕМЯ ВЫШЛО time_out
файл не удалось
захватить за указанное время;
ЗАНЯТО busy
файл не удалось
захватить немедленно.
Содержание | Части 1-5 | Части 7-8 | Части 9-11 |