Локальные сети персональных компьютеров. Работа с сервером Novell NetWare© Александр Фролов, Григорий ФроловТом 4, М.: Диалог-МИФИ, 1993, 168 стр. 3.2. Отображение дисков рабочей станцииДля обеспечения возможности работы с файлами, расположенными на дисках файл-сервера, сетевая оболочка выполняет отображение локальных дисков рабочей станции на сетевые каталоги. При этом прикладная программа, запущенная на рабочей станции, может и не заметить, что она работает не с локальным диском, а с удаленным. Разумеется, для обеспечения возможности отображения пользователь должен подключиться к файл-серверу, сообщив ему свое имя и пароль. В предыдущей главе вы научились составлять программы, подключающие пользователя к файл-серверу. Дополнительно к таблице номеров каналов серверов сетевая оболочка работает еще с тремя таблицами, необходимыми для отображения дисков. Это таблица флагов дисковых устройств (Drive Flag Table), таблица номеров каналов дисковых устройств (Drive Connection ID Table) и таблица индексов дисковых устройств (Drive Handle Table). Эти таблицы могут отображать 32 дисковых устройства, все они имеют размер 32 байта, по одному байту на одно устройство. У вас может возникнуть вопрос: почему 32 дисковых устройства, а не 26? Действительно, MS-DOS позволяет вам использовать только 26 дисковых устройств, обозначая их буквами в диапазоне от A до Z. Сетевая оболочка добавляет еще шесть устройств, которые обычно используются в качестве временных логических дисков, отображаемых на сетевые каталоги только на время работы программы. Для обозначения этих дополнительных дисков сетевая оболочка использует следующие символы:
Таблица флагов дисковых устройств (Drive Flag Table) содержит байты состояния для каждого дискового устройства рабочей станции. Пользуясь этой таблицей, программа может определить, какие диски рабочей станции локальные, а какие отображены на сетевые каталоги. Приведем список возможных значений элементов таблицы флагов:
Когда программа обращается к диску, сетевая оболочка просматривает таблицу флагов и определяет, с каким диском надо работать - с отображенным или локальным. Для того чтобы определить, на каталог какого сервера отображен тот или иной диск, программа может использовать таблицу номеров каналов дисковых устройств (Drive Connection ID Table). В этой таблице для каждого диска указан номер канала, который сетевая оболочка рабочей станции использует для работы с сервером, на чей каталог отображен данный диск. Если диск локальный или его нет совсем, для такого диска в таблице находится нулевое значение. Так как рабочая станция может образовать до 8 каналов, таблица номеров каналов дисковых устройств может содержать значения от 1 до 8 (или 0 для неиспользуемых дисков). Таблица индексов дисковых устройств (Drive Handle Table) имеет отношение к таблице каталогов, расположенной в файл-сервере. Для каждого канала файл-сервер заводит отдельную таблицу индексов дисковых устройств, в которой содержится информация о томе и каталоге, на который отображается соответствующий диск рабочей станции. Подробнее об этом мы расскажем ниже в разделе "Таблица каталогов файл-сервера". Вы можете отобразить диск рабочей станции на сетевой каталог при помощи функции AllocPermanentDirectoryHandle(), которая создает новый элемент в таблице индексов каталога, расположенной на файл-сервере. Кроме того, эта функция изменяет содержимое всех таблиц сетевой оболочки, имеющих отношение к отображению дисков рабочей станции. Приведем прототип функции AllocPermanentDirectoryHandle(): int AllocPermanentDirectoryHandle(BYTE DirectoryHandle, char *DirectoryPath, char DriveLetter, BYTE *NewDirectoryHandle, BYTE *EffectiveRightsMask); Вы можете указать путь к отображаемому сетевому каталогу либо с помощью индекса каталога через параметр DirectoryHandle, либо через полный путь к каталогу (параметр DirectoryPath), либо используя комбинированный способ. В программе DIRMAP, демонстрирующей применение этой функции (см. ниже), мы указали полный путь к отображаемому каталогу при помощи параметра DirectoryPath, а для параметра DirectoryHandle мы задали нулевое значение. Параметр DriveLetter задает отображаемый диск. Если этот диск до вызова функции AllocPermanentDirectoryHandle() отображался на другой сетевой каталог или был локальным диском рабочей станции, это никак не скажется на успехе или результате отображения. Параметр NewDirectoryHandle - указатель на переменную, в которую будет записан индекс, связанный с отображаемым каталогом. Вы можете использовать этот индекс для ссылки на каталог вместо полного имени каталога. Он будет нужен также для отмены отображения диска. Параметр EffectiveRightsMask - указатель на байт памяти, в который будет записана маска прав доступа пользователя в данном каталоге. Назначение отдельных битов этой маски мы рассмотрим ниже в разделе "Таблица каталогов файл-сервера". Отображение диска сохраняется до тех пор, пока оно не будет отменено функцией DeallocateDirectoryHandle(): int DeallocateDirectoryHandle(BYTE DirectoryHandle); Эта функция отменяет отображение диска на каталог, имеющий индекс DirectoryHandle. Для того чтобы отменить отображение диска, пользуясь его буквенным обозначением, можно воспользоваться функцией GetDirectoryHandle(), возвращающей индекс каталога для диска, заданного своим номером (0 - A, 1 - B и т. д.): DirectoryHandle = GetDirectoryHandle(argv[1][0] - 'A'); Для отображения локального диска на сетевой каталог вместо функции AllocPermanentDirectoryHandle() можно воспользоваться функцией E2h прерывания INT 21h:
Буфер запроса имеет следующий формат: struct REQUEST { WORD PacketLength; // размер пакета запроса BYTE Function; // должно быть равно 18 BYTE DirectoryHandle; // индекс каталога BYTE DriveLetter; // отображаемый диск BYTE PathLength; // длина пути к каталогу BYTE DirectoryPath[PathLength]; // путь к каталогу }; Приведем формат буфера ответа: struct REPLAY { WORD PacketLength; // размер пакета BYTE NewDirectoryHandle; // новый индекс каталога BYTE EffectiveRightsMask ; // маска прав доступа }; Для отмены отображения диска вместо функции DeallocateDirectoryHandle можно использовать функцию E2h прерывания INT 21h, заполнив буфер запроса следующим образом: struct REQUEST { WORD PacketLength; // размер пакета запроса BYTE Function; // должно быть равно 20 BYTE DirectoryHandle; // индекс каталога }; До сих пор мы рассматривали так называемое постоянное отображение дисков на сетевые каталоги. Это отображение сохраняется до тех пор, пока оно не будет отменено вызовом соответствующей функции. Однако вы можете заказать временное отображение, которое будет отменено автоматически после завершения работы программы, создавшей временное отображение. Временное отображение выполняется функцией AllocTemporaryDirectoryHandle(): int AllocTemporaryDirectoryHandle(BYTE DirectoryHandle, char *DirectoryPath, char DriveLetter, BYTE *NewDirectoryHandle, BYTE *EffectiveRightsMask); Параметры этой функции полностью аналогичны параметрам функции AllocPermanentDirectoryHandle(). Дополнительно к дискам с именами A - Z вы можете использовать диски, обозначаемые следующими символами: [, \, ], ^, _, '. Для временного отображения диска на сетевой каталог вы можете воспользоваться функцией E2h прерывания INT 21h. Вам надо заполнить буфер запроса аналогично тому, как это нужно для создания постоянного отображения, но в поле Function необходимо указать значение 19. Формат буфера ответа полностью аналогичен формату, используемому при постоянном отображении. Для получения адресов таблиц можно воспользоваться функцией EFh прерывания INT 21h:
3.2.1. Программа WKSTABLEПриведем программу, отображающую состояние внутренних таблиц сетевой оболочки. Кроме таблиц отображения дисковых устройств программа показывает содержимое таблицы номеров каналов и таблицы имен файл-серверов, с которыми рабочая станция создала каналы. Программа WKSTABLE (листинг 8) получает адреса всех таблиц и выводит их в стандартный поток вывода в соответствующем формате. Вы можете подключиться к нескольким серверам и выполнить отображение дисков утилитами attach.exe и map.exe из каталога SYS:PUBLIC, а затем запустить программу и посмотреть содержимое таблиц. // ============================================================ // Листинг 8. Отображение содержимого таблиц сетевой оболочки. // Файл wkstable\wkstable.cpp // // (C) A. Frolov, 1993 // ============================================================ #include <stdlib.h> #include <stdio.h> #include <dos.h> #include <conio.h> #define BYTE unsigned char // Формат таблицы номеров каналов для сетевой оболочки struct ConnectionIDTable { BYTE InUseFlag; BYTE OrderNumber; BYTE NetworkNumber[4]; BYTE NodeAddress[6]; BYTE SocketNumber[2]; BYTE ReceiveTimeout[2]; BYTE RoutingNode[6]; BYTE PacketSequenceNumber; BYTE ConnectionNumber; BYTE ConnectionStatus; BYTE MaximumTimeout[2]; BYTE Reserved[5]; }; void GetTableAddress(int Table, char far * *TableAddress); void ShowTable(char far *DriveHandleTable); void ShowConnIDTable(struct ConnectionIDTable far *ConnIDTable); void ShowServerNameTable(char far *ServerNameTable); void main(void) { // Указатели на таблицы сетевой оболочки char far *DriveHandleTable; char far *DriveFlagTable; char far *DriveServerTable; char far *ServerMappingTable; char far *ServerNameTable; struct ConnectionIDTable far *ConnIDTable; // Получаем указатели на таблицы GetTableAddress(0, &DriveHandleTable); GetTableAddress(1, &DriveFlagTable); GetTableAddress(2, &DriveServerTable); GetTableAddress(3, &ServerMappingTable); GetTableAddress(4, &ServerNameTable); printf("\nТаблицы сетевой оболочки, (C) Frolov A., 1993\n" "---------------------------------------------\n"); // Отображаем содержимое таблицы индексов дисковых устройств printf("\nDrive Handle Table (%Fp)\n", DriveHandleTable); printf( "------------------\n"); ShowTable(DriveHandleTable); // Отображаем содержимое таблицы флагов дисковых устройств printf("\nDrive Flag Table (%Fp)\n", DriveFlagTable); printf( "----------------\n"); ShowTable(DriveFlagTable); // Отображаем содержимое таблицы отображения дисков на серверы printf("\nDrive Server Table (%Fp)\n", DriveServerTable); printf( "------------------\n"); ShowTable(DriveServerTable); printf("Нажмите любую клавишу для продолжения...\n"); getch(); // Отображаем содержимое таблицы каналов с серверами ConnIDTable = (struct ConnectionIDTable far *)ServerMappingTable; printf("\nConnection ID Table (%Fp)\n", ConnIDTable); printf( "-------------------\n"); ShowConnIDTable(ConnIDTable); // Отображаем содержимое таблицы имен серверов printf("\nServer Name Table (%Fp)\n", ServerNameTable); printf( "-----------------\n"); ShowServerNameTable(ServerNameTable); } // =========================================================== // Функция для отображения таблицы имен серверов // =========================================================== void ShowServerNameTable(char far *ServerNameTable) { for(int i=0; i<8; i++) { if(*(ServerNameTable + 48*i) != '\0') printf("%d: %Fs\n", i+1, ServerNameTable + 48*i); else printf("%d: Не используется\n", i+1); } } // =========================================================== // Функция для отображения таблицы каналов рабочей станции // =========================================================== void ShowConnIDTable(struct ConnectionIDTable far *ConnIDTable) { printf("Порядковый номер:\t"); for(int i=0; i<8; i++) { printf("%d ", i+1); } printf("\nНомер канала:\t\t"); for(i=0; i<8; i++) { printf("%02.2X ", (ConnIDTable + i)->ConnectionNumber); } printf("\nСостояние канала:\t"); for(i=0; i<8; i++) { printf("%02.2X ", (ConnIDTable + i)->ConnectionStatus); } printf("\n"); } // =========================================================== // Функция для вывода содержимого таблиц отображения // дисковых устройств // =========================================================== void ShowTable(char far *Table) { printf("A B C D E F G H I J K L M N " "O P Q R S T U V W X Y Z\n"); for(int i=0; i<26; i++) { printf("%02.2X ",(unsigned char)*(Table +i)); } printf("\n[ \\ ] ^ _ '\n"); for(i=26; i<32; i++) { printf("%02.2X ",(unsigned char)*(Table +i)); } printf("\n"); } // =========================================================== // Функция для получения указателей на таблицы // оболочки рабочей станции // =========================================================== void GetTableAddress(int Table, char far* *TableAddress) { union REGS regs; struct SREGS sregs; regs.h.ah = 0xef; regs.h.al = Table; intdosx(®s, ®s, &sregs); FP_OFF(*TableAddress) = regs.x.si; FP_SEG(*TableAddress) = sregs.es; } Мы запустили программу в сети, содержащей четыре файл-сервера, и вот что увидели на экране: Таблицы сетевой оболочки, (C) Frolov A., 1993 --------------------------------------------- Drive Handle Table (C143:01A0) ------------------ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 00 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00 02 02 02 00 06 03 04 05 [ \ ] ^ _ ' 00 00 00 00 00 00 Drive Flag Table (C143:01C0) ---------------- A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 80 80 80 80 80 80 80 80 80 01 00 00 00 00 00 00 00 00 01 01 01 00 01 01 01 01 [ \ ] ^ _ ' 00 00 00 00 00 00 Drive Server Table (C143:01E0) ------------------ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 04 03 02 00 01 01 01 01 [ \ ] ^ _ ' 00 00 00 00 00 00 Нажмите любую клавишу для продолжения... Connection ID Table (C143:0254) ------------------- Порядковый номер: 1 2 3 4 5 6 7 8 Номер канала: 04 0B 01 01 FF FF FF FF Состояние канала: FF FF FF FF 00 00 00 00 Server Name Table (C143:0354) ----------------- 1: SYSPRG 2: SMARTNET 3: NETLAB 4: WINLAB 5: Не используется 6: Не используется 7: Не используется 8: Не используется Из таблицы Server Name Table видно, что рабочая станция создала каналы с серверами SYSPRG, SMARTNET, NETLAB и WINLAB. Анализируя содержимое таблицы Drive Flag Table, можно сделать вывод, что рабочая станция имеет локальные диски от A: до I:, диски J:, S:, T:, U:, W:, X:, Y:, Z: постоянно отображены на сетевые каталоги, т. е. это сетевые диски. Из таблицы Drive Server Table видно, что диски J:, W:, X:, Y:, Z: отображены на каталоги сервера SYSPRG (номер канала соответствует позиции имени файл-сервера в таблице имен). Диск U: отображен на сервер SMARTNET (канал 2), диск T: - на сервер NETLAB (канал 3), диск S: - на сервер WINLAB (канал 4). Таблица Drive Handle Table позволяет сетевой оболочке определить, на какие конкретно каталоги отображены соответствующие диски, так как она содержит индекс таблицы отображения соответствующего файл-сервера. Из таблицы Connection ID Table можно получить информацию о том, какие из 8 имеющихся каналов задействованы и какие номера каналов используют серверы для работы с нашей станцией. Например, сервер SYSPRG использует канал с номером 04h, сервер SMARTNET - канал с номером 0Bh, а серверы NETLAB и WINLAB - каналы с номером 01h. Пусть вас не смущает, что последние два сервера используют один и тот же номер канала: эти номера соответствуют таблице, расположенной в сервере, а не в рабочей станции. 3.2.2. Программа DIRMAPПри помощи программы DIRMAP (листинг 9) вы сможете отображать локальные диски рабочей станции на сетевые каталоги. В качестве первого параметра при запуске программы необходимо задать букву отображаемого диска, в качестве второго - полный путь к сетевому каталогу (без имени сервера). // =================================================== // Листинг 9. Отображение локальных дисков на // сетевые каталоги // Файл dirmap\dirmap.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 AllocPermanentDirectoryHandle(BYTE, char *, char, BYTE*, BYTE*); void main(int argc, char *argv[]) { char MajorVersion=0; char MinorVersion=0; char Revision=0; BYTE NewDirectoryHandle; BYTE RightsMask; int ccode; printf("\n*DIRMAP* (C) Frolov A., 1993\n"); // Проверяем наличие сетевой оболочки asm push si GetNetWareShellVersion(&MajorVersion, &MinorVersion, &Revision); asm pop si if(MajorVersion == 0) { printf("\nОболочка NetWare не загружена\n"); return; } // Необходимо задать букву, обозначающую имя // локального диска и путь к сетевому каталогу if(argc < 3) { printf("Укажите локальный диск и путь " "к каталогу, \nнапример: dirmap f sys:users\n"); return; } // Параметры должны быть заданы заглавными буквами strupr(argv[1]); strupr(argv[2]); // Создаем новый индекс каталога и отображаем диск ccode = AllocPermanentDirectoryHandle(0, argv[2], argv[1][0], &NewDirectoryHandle, &RightsMask); // Если ошибок не было, выводим индекс каталога // и маску прав для каталога if(!ccode) printf("Индекс каталога: %d, маска прав: %02.2X\n", NewDirectoryHandle, RightsMask); else printf("Ошибка %02.2X\n", ccode); } 3.2.3. Программа DIRUNMAPПрограмма DIRUNMAP (листинг 10) выполняет отмену отображения локального диска на сетевой каталог. Ей необходимо указать один параметр - букву, обозначающую диск, для которого необходимо отменить отображение. // =================================================== // Листинг 10. Отмена отображения локального диска на // сетевой каталог // Файл dirunmap\dirunmap.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" BYTE GetDirectoryHandle(BYTE); extern "C" int DeallocateDirectoryHandle(BYTE); void main(int argc, char *argv[]) { char MajorVersion=0; char MinorVersion=0; char Revision=0; BYTE DirectoryHandle; int ccode; printf("\n*DIRUNMAP* (C) Frolov A., 1993\n"); // Проверяем наличие сетевой оболочки asm push si GetNetWareShellVersion(&MajorVersion, &MinorVersion, &Revision); asm pop si if(MajorVersion == 0) { printf("\nОболочка NetWare не загружена\n"); return; } // Необходимо задать букву, обозначающую имя // локального диска и путь к сетевому каталогу if(argc < 2) { printf( "Укажите локальный диск, например: dirunmap f\n"); return; } // Параметр должен быть задан заглавной буквой strupr(argv[1]); // Получаем индекс каталога, на который отображен указанный диск DirectoryHandle = GetDirectoryHandle(argv[1][0] - 'A'); // Если диск не отображен на сетевой каталог, // выводим сообщение об ошибке if(DirectoryHandle) printf("Индекс каталога: %d\n", DirectoryHandle); else { printf("Диск не отображен на сетевой каталог\n"); return; } // Отменяем отображение диска ccode = DeallocateDirectoryHandle(DirectoryHandle); // Если ошибок не было, выводим индекс каталога // и маску прав для каталога if(ccode) printf("Ошибка %02.2X\n", ccode); else printf("Диск %c удален\n", argv[1][0]); } |