Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform
Шрифт:
В функции my_read, чтобы решить, какие операции надо выполнить, мы анализируем поле mode атрибутной записи. Если макрос S_ISDIR говорит, что это каталог, мы вызываем функцию my_read_dir; если макрос S_ISREG говорит, что это файл, мы вызываем функцию my_read_file. (Отметим, что если мы не можем разобрать, что это такое, мы возвращаем клиенту EBADF, указывая ему этим, что что-то здесь не так.)
Приведенный ниже код ничего не знает о наших специальных устройствах, да ему, собственно, и дела до них нет — он просто принимает решение на основе стандартных общеизвестных данных.
Вот тут-то все веселье и начинается. С точки зрения высокого уровня, мы выделяем буфер (он называется reply_msg), в котором собираемся разместить результат операции. Затем мы используем dp, чтобы «прогуляться» по буферу, заполняя его по ходу дела элементами
На первый взгляд этот код может показаться неэффективным; мы используем функцию sprintf для создания двухбайтового имени файла (символ имени файла и признак конца строки NULL) в буфере длиной _POSIX_PATH_MAX (то есть 256) байт. Это делается для того, чтобы сделать код по возможности универсальным.
Наконец, обратите внимание, что мы используем поле offset в OCB для указания, для какого конкретного файла мы в данный момент генерируем структуру
Возврат данных клиенту осуществляется «обычным» способом при помощи функции MsgReply. Заметьте, что поле состояния (status) функции MsgReply используется для указания числа отправленных клиенту байт.
В функции my_read_file мы видим код, почти аналогичный простому примеру функции чтения, который приведен выше в данном разделе. Единственная странная вещь, которую мы здесь делаем — поскольку мы знаем, что возвращается всегда только один байт данных, значит, если параметр nbytes не равен нулю, то он должен быть равен единице (и ничему другому). Таким образом, мы можем создавать данные, подлежащие возврату, непосредственным заполнением символьной переменной string. Обратите внимание, как мы используем поле inode атрибутной записи для определения, какие данные возвращать. Это обычный прием для администраторов, обслуживающих несколько ресурсов. Дополнительным трюком было бы расширить атрибутную запись (мы говорили об этом в разделе «Расширение атрибутной записи») и хранить непосредственно в ней либо сами данные, либо указатель на них.