Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Локальные сети персональных компьютеров. Работа с сервером Novell NetWare

© Александр Фролов, Григорий Фролов
Том 4, М.: Диалог-МИФИ, 1993, 168 стр.

[Назад] [Содеожание] [Дальше]

3.3. Таблица каталогов файл-сервера

Вся информация о содержимом каталогов файл-сервера находится в таблице каталогов. Таблица каталогов по своему назначению напоминает каталоги MS-DOS: в ней находится информация об именах каталогов и файлов, байты атрибутов, информация о дате создания, идентификатор пользователя, создавшего файл или каталог, информация о правах доступа и т. д.

Для просмотра каталогов в операционной системе MS-DOS имеются соответствующие функции, о чем мы рассказывали в первом томе "Библиотеки системного программиста". Разумеется, программа может просматривать сетевые каталоги с помощью этих функций. Однако если вы воспользуетесь функциями, специально предназначенными для просмотра содержимого каталогов, вы сможете узнать имя пользователя, создавшего каталог или файл, а также получить информацию о правах доступа к каталогу или файлу.

Сетевая оболочка Novell NetWare имеет две разные функции для поиска подкаталогов в каталоге и для поиска файлов в каталоге (MS-DOS получает информацию сразу и о файлах, и о подкаталогах). В этом разделе мы расскажем о поиске каталогов, а файлами займемся позже, в главе "Работа с файлами".

Библиотека NetWare C Interface содержит функцию ScanDirectoryInformation(), предназначенную для просмотра содержимого каталогов. С ее помощью вы можете получить информацию о подкаталогах любого сетевого каталога.

Приведем прототип функции:

int ScanDirectoryInformation(BYTE DirectoryHandle,
        char *SearchDirectoryPath, int *SequenceNumber,
        char *DirectoryName, BYTE *CreationDateAndTime,
        long *OwnerObjectID, BYTE *MaximumRightsMask);


С помощью параметров DirectoryHandle и SearchDirectoryPath задается каталог, содержимое которого надо просмотреть. Параметр DirectoryHandle - это индекс в таблице дисков, которую файл-сервер поддерживает для каждой рабочей станции. Когда диск рабочей станции отображается на каталог файл-сервера, создается новый элемент в таблице дисков файл-сервера. Индекс DirectoryHandle однозначно соответствует сетевому каталогу, на который отображается локальный диск рабочей станции.

Вы можете задать в качестве параметра DirectoryHandle нулевое значение, при этом параметр SearchDirectoryPath должен указывать на текстовую строку, содержащую полный путь к исследуемому каталогу. В строке могут использоваться символы "*" и "?", которые трактуются так же, как и в MS-DOS. Например, для поиска всех подкаталогов каталога SYS:USERS вы можете задать 0 в поле DirectoryHandle и строку "SYS:USERS\*" в поле SearchDirectoryPath.

Имя файл-сервера не указывается, так как запрос направляется к предпочтительному, текущему или первичному серверу, в зависимости от того, существует ли предпочтительный сервер или текущий сервер. Если был задан предпочтительный сервер, функция ScanDirectoryInformation() обращается к предпочтительному серверу. Если предпочтительный сервер не был задан и на рабочей станции текущим является диск, отображенный на сетевой каталог, функция ScanDirectoryInformation() обращается к файл-серверу, содержащему этот каталог. Если текущий диск рабочей станции является локальным, функция ScanDirectoryInformation() обращается к первичному серверу.

Параметр SequenceNumber - указатель на слово, которое должно содержать нулевое значение при первом вызове функции ScanDirectoryInformation(). Для получения информации о всех подкаталогах вам придется вызывать эту функцию в цикле, при этом слово, на которое указывает параметр SequenceNumber, будет автоматически увеличиваться самой функцией.

Остальные четыре параметра - указатели на переменные, в которые будут записаны возвращаемые значения.

В область памяти, на которую указывает параметр DirectoryName, после успешного вызова функции будет записано имя обнаруженного подкаталога. Размер этой области памяти должен составлять 16 байт. Вызывая в цикле функцию ScanDirectoryInformation(), программа будет получать в поле, адресуемом параметром DirectoryName, имена найденных подкаталогов.

Параметр CreationDateAndTime указывает на область памяти, размером 4 байта, в которую будет записана информация о дате и времени создания найденного подкаталога. На рис. 1 приведен формат этой информации. К номеру года, возвращенному в первом байте, необходимо добавить число 80.

Рис.1. Формат даты и времени

Параметр OwnerObjectID - указатель на слово, в котором будет записан идентификатор пользователя, создавшего каталог. По этому идентификатору с помощью функции GetBinderyObjectName() вы легко сможете получить имя пользователя.

Параметр MaximumRightsMask - указатель на байт, в который будет записано значение маски прав доступа, связанное с данным каталогом. Маска используется для определения возможности доступа к каталогу и определяется при создании каталога. Каждый бит маски, установленный в 1, разрешает соответствующий вид доступа:

Номер бита Доступ
0 Чтение файлов
1 Запись в файлы
2 Открытие файлов
3 Создание файлов
4 Удаление файлов
5 Можно создавать подкаталоги и задавать для создаваемых подкаталогов права доступа
6 Поиск файлов в каталоге
7 Изменение атрибутов файлов

Функция ScanDirectoryInformation() при успешном завершении возвращает нулевое значение, в противном случае - код ошибки:

Код ошибки Значение
0x98 Заданный сетевой том не существует
0x9B Неправильное значение параметра индекса каталога
0x9C Неправильный путь к каталогу

Для просмотра подкаталогов в заданном каталоге вместо функции ScanDirectoryInformation() можно использовать функцию E2h прерывания INT 21h:

На входе: AH = E2h;
DS:SI = Адрес буфера запроса;
ES:DI Адрес буфера ответа.
На выходе: AL Код ошибки или 0, если операция завершилась без ошибок.

Буфер запроса имеет следующий формат:

struct REQUEST {
        WORD    PacketLength;        // размер пакета запроса
        BYTE    Function;            // должно быть равно 2
        BYTE    DirectoryHandle;     // индекс каталога
        WORD    SequenceNumber;      // порядковый номер
        BYTE    PathLength;          // длина поля пути
        BYTE    SearchDirectoryPath[PathLength]; // путь поиска
};


Приведем формат буфера ответа:

struct REPLAY {
        WORD    PacketLength;      // размер пакета
        BYTE    DirectoryName[16]; // имя найденного каталога
        BYTE    CreationDate[2];   // дата создания каталога
        BYTE    CreationTime[2];   // время создания каталога
        long    OwnerObjectID;     // идентификатор пользователя,
                                   // создавшего каталог
        BYTE            MaximumRightsMask; // маска прав доступа
        BYTE            Reserved;          // зарезервировано
        WORD    SubDirNumber;      // номер подкаталога в
                                   // каталоге
};


В процессе просмотра содержимого каталога программа должна вызывать эту функцию в цикле, задавая каждый раз (кроме первого) значение поля SequenceNumber в буфере запроса равным значению SubDirNumber, полученному в буфере ответа после предыдущего вызова функции. При первом вызове функции значение поля SequenceNumber должно быть равно нулю. Учтите, что поля SubDirNumber и SequenceNumber имеют "перевернутый" формат, т. е. младший байт поля записан по старшему адресу.

Если при вызове функции был найден подкаталог, соответствующий образцу, заданному в поле SearchDirectoryPath, регистр AL будет содержать нулевое значение.

3.3.1. Программа DIRSCAN

С помощью программы DIRSCAN вы сможете получить список подкаталогов для каталога, путь к которому задан в качестве параметра при запуске программы.

Для преобразования идентификатора пользователя, создавшего каталог,
в имя мы использовали функцию GetBinderyObjectName() из библиотеки NetWare C Interface:

int GetBinderyObjectName(long ObjectID,
         char *ObjectName, WORD *ObjectType);


Функция ищет в базе объектов запись с идентификатором ObjectID и в случае успеха записывает в переменные, адресуемые параметрами ObjectName и ObjectType, имя и тип объекта. В случае успешного поиска функция возвращает нулевое значение.

Итак, исходный текст программы DIRSCAN:

// ===================================================
// Листинг 11. Просмотр списка подкаталогов
// сетевого каталога
// Файл dirscan\dirscan.cpp
//
// (C) A. Frolov, 1993
// ===================================================

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

#define BYTE unsigned char
#define WORD unsigned int

extern "C" int GetNetWareShellVersion(char *,char *, char *);
extern "C" int ScanDirectoryInformation(BYTE, char *, int *,
                                          char *, BYTE *, long *, BYTE *);
extern "C" int GetBinderyObjectName(long, char *, WORD *);

void main(int argc, char *argv[]) {

        char MajorVersion=0;
        char MinorVersion=0;
        char Revision=0;

        int SequenceNumber;
        char DirectoryName[16];
        BYTE CreationDataAndTime[4];
        long OwnerObjectID;
        BYTE RightsMask;
        int ccode;

        char ObjectName[48];
        WORD ObjectType;

        printf("\n*DIRSCAN* (C) Frolov A., 1993\n");

// Проверяем наличие сетевой оболочки

        asm push si
        GetNetWareShellVersion(&MajorVersion,
                        &MinorVersion, &Revision);
        asm pop si

        if(MajorVersion == 0) {
                printf("\nОболочка NetWare не загружена\n");
                return;
        }
// В качестве аргумента необходимо задать
// путь к просматриваемому каталогу в виде   SYS:USERS\*

        if(argc < 2) {
                printf("Укажите путь к каталогу, "
                        "например: dirscan sys:users\\*\n");
                return;
        }
        printf("Содержимое каталога %s\n", argv[1]);
        printf("--------------------------------------------\n");
        printf("Имя     \tКто владелец каталога\n");
        printf("--------------------------------------------\n");

// Путь должен быть задан заглавными буквами

        strupr(argv[1]);

// Цикл просмотра каталога

        for(SequenceNumber = 0;;) {

// Получаем информацию о содержимом каталога

                ccode = ScanDirectoryInformation(0, argv[1], &SequenceNumber, DirectoryName,
CreationDataAndTime, &OwnerObjectID, &RightsMask);

// Если были ошибки или каталог пуст, завершаем цикл

                if(ccode) break;
                if(DirectoryName[0] == '\0') break;

// Выводим имя каталога

                printf("%-12s", DirectoryName);

// Если для каталога определен владелец,
// получаем и выводим имя владельца

                if(OwnerObjectID) {
                        GetBinderyObjectName(OwnerObjectID, ObjectName,  &ObjectType);
                        printf("\t%-12s \n", ObjectName);
                }
                else
                        printf("\t <Нет сведений о владельце> \n");
        }
}


[Назад] [Содеожание] [Дальше]