Локальные сети персональных компьютеров. Работа с сервером 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, разрешает соответствующий вид доступа:
Функция ScanDirectoryInformation() при успешном завершении возвращает нулевое значение, в противном случае - код ошибки:
Для просмотра подкаталогов в заданном каталоге вместо функции ScanDirectoryInformation() можно использовать функцию E2h прерывания INT 21h:
Буфер запроса имеет следующий формат: 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 вы сможете получить список подкаталогов для каталога, путь к которому задан в качестве параметра при запуске программы. Для преобразования идентификатора
пользователя, создавшего каталог, 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"); } } |