Локальные сети персональных компьютеров. Работа с сервером 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");
}
}
|

