4. Работа с файлами

В этом разделе мы расскажем вам об использовании некоторых, самых интересных, на наш взгляд, функций сетевой оболочки Novell NetWare, предназначенных для работы с файлами.

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

4.1. Атрибуты файлов

По сравнению с файлами MS-DOS файлы, расположенные на файл-сервере Novell NetWare, имеют больше атрибутов. В этом разделе мы рассмотрим эти атрибуты.

В отличие от MS-DOS файловая система Novell NetWare для хранения атрибутов файлов использует не один, а два байта. Первый байт называется байтом атрибутов (File Attributes Byte), второй - байтом расширенных атрибутов (Extended File Attributes Byte).

Приведем назначение отдельных битов байта атрибутов:

Бит Назначение
0 Read Only: файл можно читать, но нельзя в него писать. Этот файл нельзя также удалять или переименовывать
1 Hidden: скрытый файл, не появляется в списке файлов при поиске в каталоге обычными средствами
2 System: системный файл, не появляется в списке файлов при поиске в каталоге обычными средствами
3 Execute Only: файл может быть загружен только для выполнения. Этот файл нельзя читать или перезаписывать. В операционной системе Novell NetWare не существует средств для сброса бита Execute Only; поэтому, если вы установите этот бит, вы навсегда потеряете доступ к файлу на чтение и запись
4 Subdirectory: данный элемент оглавления каталога описывает не файл, а подкаталог
5 Archive: этот бит установлен, если после выполнения операции выгрузки файла сам файл был изменен
6 Зарезервировано
7 Shareable: к данному файлу разрешен одновременный доступ со стороны нескольких пользователей, расположенных на разных рабочих станциях

Обратим ваше внимание на бит Execute Only. Если вы установите этот бит, вызвав соответствующую функцию или воспользовавшись утилитами Novell NetWare, никто (даже супервизор) не будет иметь доступа на чтение к этому файлу. Такая возможность полезна для защиты программ от несанкционированного копирования и дезассемблирования, однако этот способ обладает рядом недостатков.

Во-первых, вы не можете установить бит Execute Only у оверлеев, так как перед запуском их надо загрузить в память, а такая операция запрещена для "только выполняемых" файлов. Файлы, содержащие программы для Microsoft Windows, также нельзя отмечать как Execute Only из-за того, что они содержат ресурсы, подгружаемые после запуска программы.

Во-вторых, никто не помешает злоумышленнику поймать вашу программу в памяти уже после ее запуска. Для этого он может воспользоваться, например, резидентными отладчиками, такими, как AFD или Turbo Debugger. Так что не переоценивайте защиту при помощи атрибута Execute Only.

Если вы случайно установили бит Execute Only для файла, содержащего данные, можете смело удалять этот файл - вам никогда не удастся сбросить бит Execute Only и прочитать содержимое файла.

Байт расширенных атрибутов имеет следующий формат:

Бит Назначение
0, 1, 2 Search Mode: биты 0, 1 и 2 задают режим поиска программного файла при запуске программы на выполнение. Мы не будем рассматривать эти биты для сокращения объема книги, подробности о режимах поиска и дисках поиска вы можете узнать из руководства по библиотеке NetWare C Interface
3 Зарезервировано
4 Transaction Bit: при работе с файлом используется обработка транзакций. Файл, у которого установлен этот бит, не может быть удален или переименован
5 Index: для файла размером больше 2 Мбайт для более быстрого доступа организуется индекс по таблице FAT. Этот бит не используется в Novell NetWare версии 3.11
6 Зарезервировано
7 Зарезервировано

4.2. Поиск файлов

Для поиска файлов в каталоге вы можете воспользоваться функцией _ScanFileInformation() (в документации по библиотеке Netware C Interface эта функция называется ScanFileInformation(), однако в самой библиотеке нет функции с этим названием, зато есть функция _ScanFileInformation(), которая делает то же самое). Приведем прототип функции:

int _ScanFileInformation(BYTE DirectoryHandle,
   char *FilePath, BYTE SearchAttributes, int *SequenceNumber,
   char *FileName, BYTE *FileAttributes, 
   BYTE *ExtendedFileAttributes, long *FileSize,
   char *CreationDate, char *LastAccessDate,
   char *LastUpdateDateAndTime, char *LastArchiveDateAndTime,
   long *FileOwnerID);


Параметр DirectoryHandle при вызове функции может содержать индекс просматриваемого каталога или ноль. В последнем случае путь к просматриваемому каталогу должен быть задан через параметр FilePath в виде текстовой строки, закрытой двоичным нулем.

Параметр SearchAttributes определяет, какие типы файлов нужно найти. Этот параметр может принимать следующие значения:

Параметр Значение
0 Обычные файлы
2 Обычные и скрытые файлы
4 Обычные и системные файлы
6 Обычные, скрытые и системные файлы

Параметр SequenceNumber при первом вызове функции должен указывать на переменную, которая имеет значение 0xFFFF. Когда программа будет просматривать содержимое каталога, вызывая функцию в цикле, содержимое этой переменной будет изменяться автоматически.

Параметр FileName должен указывать на буфер размером 15 байт, в который будет записано имя найденного файла.

Атрибуты и расширенные атрибуты будут записаны в байты памяти, которые необходимо указать при помощи параметров FileAttributes и ExtendedFileAttributes.

Размер найденного файла будет записан в переменную, заданную при помощи параметра FileSize.

Сведения о дате создания файла и дате последнего доступа к файлу будут записаны в буферы размером 2 байта, заданные соответственно параметрами CreationDate и LastAccessDate.

Дата и время последнего обновления содержимого файла будут записаны в буфер размером 4 байта, заданный параметром LastUpdateDateAndTime, а дата и время выгрузки - в аналогичный буфер, заданный параметром LastArchiveDateAndTime.

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

Функция поиска файлов _ScanFileInformation() возвращает 0 при успешном завершении или код ошибки:

Код ошибки Значение
0x89 У программы нет прав для поиска файлов
0xFF Файл не найден

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

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

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

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


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

struct REPLAY {
        WORD    PacketLength;        // размер пакета
        WORD    SequenceNumber;      // номер для просмотра
        BYTE    FileName[15];        // имя файла
        BYTE    FileAttributes;      // атрибуты файла
        BYTE    ExtendedFileAttributes; // расширенные 
                                        // атрибуты файла
        long    FileSize;               // размер файла в байтах
        BYTE    CreationDate[2];        // дата создания
        BYTE    LastAccessDate[2];      // дата последнего доступа
        BYTE    LastUpdateDateAndTime[4];  // дата и время
                                           // обновления
        BYTE    LastArchiveDateAndTime[4]; // дата и время
                                           // выгрузки
        BYTE    Reserved[60]; // зарезервировано
};


При вызове этой функции в цикле в первый раз в поле SequenceNumber буфера запроса необходимо записать значение 0xFFFF. При последующих вызовах необходимо уменьшать на единицу значение, полученное в поле SequenceNumber буфера ответа и записывать его в поле SequenceNumber буфера запроса. Следует учитывать, что байты в поле SequenceNumber записаны в обратном порядке, поэтому перед уменьшением необходимо переставить байты. Это можно сделать при помощи функции IntSwap() из библиотеки NetWare C Interface.

4.2.1. Программа FSCAN

Приведем программу FSCAN (листинг 17), которая выводит список файлов, расположенных в каталоге, путь к которому задается в качестве параметра при запуске программы. Для каждого найденного в каталоге файла программа выводит имя файла, его размер, байт атрибутов и байт расширенных атрибутов, а также имя пользователя, создавшего файл.

// ===================================================
// Листинг 17. Просмотр списка файлов в каталоге
// Файл fscan\fscan.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 _ScanFileInformation(BYTE, char *, BYTE, int *,
                                        char *, BYTE *, BYTE *, long *,
                                        char *, char *, char *, char *, long *);
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 FileName[16];
        BYTE FileAttributes;
        BYTE ExtendedFileAttributes;
        long FileSize;
        BYTE CreationDate[2];
        BYTE LastAccessDate[2];
        BYTE LastUpdateDateAndTime[4];
        BYTE LastArchiveDateAndTime[4];
        long FileOwnerID;

        int ccode;

        char ObjectName[48];
        WORD ObjectType;

        printf("\n*FSCAN* (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Размер\tАтрибуты\tВладелец\n");
        printf("--------------------------------------------"
                        "-------------\n");

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

        strupr(argv[1]);

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

        for(SequenceNumber = 0xFFFF;;) {

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

                ccode = _ScanFileInformation(0, argv[1], 6,
              &SequenceNumber, FileName, &FileAttributes,
              &ExtendedFileAttributes, &FileSize,
              CreationDate, LastAccessDate, LastUpdateDateAndTime, 
              LastArchiveDateAndTime, &FileOwnerID);

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

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

// Выводим имя файла

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

// Выводим размер файла

                printf("\t%ld", FileSize);

// Выводим байт атрибутов и байт расширенных атрибутов

                printf("\t%02.2X %02.2X\t", FileAttributes,
                                ExtendedFileAttributes);
// Если для каталога определен владелец,
// получаем и выводим имя владельца




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


Приведем фрагменты выдачи программы FSCAN при просмотре файлов из каталога SYS:SYSTEM файл-сервера Novell NetWare версии 3.11:

*FSCAN* (C) Frolov A., 1993
Список файлов в каталоге sys:system\*
---------------------------------------------------------
Имя         Размер  Атрибуты        Владелец
---------------------------------------------------------
SYS$LOG.ERR     10852   20 00           SYSPRG       
README.BTR      6689    00 00           SUPERVISOR   

***************

CLIB.NLM        232842  81 00           SYSPRG       
3C503.LAN       11856   81 00           SYSPRG       
PS2MFM.DSK      8759    81 00           SYSPRG       
INSTALL.NLM     160613  81 00           SYSPRG       
NE2000.LAN      11636   81 00           SYSPRG       

***************

BCONNLM.HLP     1583    81 00           SYSPRG       
BROUTER.NLM     15884   81 00           SYSPRG       
BTRIEVE.NLM     64616   01 00           SYSPRG       
NET$OBJ.SYS     2560    26 10           FROLOV       
BTRIEVE.TRN     4096    00 00           SYSPRG       
PRODUCTS.DAT    5120    00 00           SYSPRG       
AUTOEXEC.NCF    203     00 00           SYSPRG       
MODEM.CFG       46      00 00           FROLOV       
IBM$EMS.HLP     84047   00 00           FROLOV       
IBM$DRV.OVL     2144    00 00           FROLOV       
IBM$EMS.OVL     405     00 00           FROLOV       
VIR.DAT         29934   20 00           FROLOV       
NET$PROP.SYS    8364    26 10           FROLOV       
NET$VAL.SYS     33654   26 10           FROLOV       
NETSHLD.NLM     246146  20 00           FROLOV       
VIR$CFG.DAT     838     20 00           SYSPRG       
VIR$LOG.DAT     3146    20 00           SYSPRG       


Файлы с атрибутами 00h и 20h - обычные файлы. Файлы с атрибутами 26h - скрытые и системные. Файл BTRIEVE.NLM имеет байт атрибутов 01, этот файл можно только читать. Файлы с атрибутом 81 - только читаемые файлы, к которым возможен одновременный доступ со стороны нескольких пользователей.

В приведенном выше списке есть файлы, у которых установлен бит Transaction Bit. Для этих файлов включен механизм обработки транзакций, гарантирующий сохранность содержимого файла при аварии в электропитающей сети или по другим аналогичным причинам.

4.3. Изменение атрибутов

Для изменения атрибутов файлов, а также другой информации, такой, как время создания файла и идентификатор владельца, можно воспользоваться функцией SetFileInformation():

int SetFileInformation(BYTE DirectoryHandle,
   char *FilePath, BYTE SearchAttributes, 
   BYTE FileAttributes, 
   BYTE ExtendedFileAttributes,
   char *CreationDate, char *LastAccessDate,
   char *LastUpdateDateAndTime, 
   char *LastArchiveDateAndTime,
   long *FileOwnerID);


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

Функция SetFileInformation() возвращает 0 при успешном завершении или код ошибки.

Для изменения атрибутов файлов и другой информации о файлах можно использовать функцию E3h прерывания INT 21h:

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

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

struct REQUEST {
        WORD    PacketLength;        // размер пакета запроса
        BYTE    Function;            // должно быть равно 16
        BYTE    FileAttributes;      // атрибуты файла
        BYTE    ExtendedFileAttributes; // расширенные 
                                        // атрибуты файла
        long    Reserved;               // зарезервировано
        BYTE    CreationDate[2];        // дата создания
        BYTE    LastAccessDate[2];      // дата последнего доступа
        BYTE    LastUpdateDateAndTime[4];  // дата и время
                                           // обновления
        BYTE    LastArchiveDateAndTime[4]; // дата и время выгрузки
        BYTE    Reserved[60];              // зарезервировано
        BYTE    DirectoryHandle;     // индекс каталога
        BYTE    SearchAttributes;    // тип файлов для поиска
        BYTE    PathLength;          // длина поля пути
        BYTE    DirectoryPath[PathLength]; // путь к каталогу
};


Для изменения байта расширенных атрибутов удобно использовать функцию SetExtendedFileAttributes():

int SetExtendedFileAttributes(char *FilePath,
                BYTE *NewExtendedFileattributes);


Параметр FilePath задает путь к файлу, а параметр NewExtendedFileattributes - новое значение для байта расширенных атрибутов.

Функция возвращает 0 при успешном завершении или код ошибки:

Код ошибки Значение
0xFE У программы нет прав для изменения атрибута
0xFF Файл не найден

Для того чтобы узнать байт расширенного атрибута файла, используйте функцию GetExtendedFileAttributes():

int GetExtendedFileAttributes(char *FilePath,
                BYTE *ExtendedFileattributes);


Параметр FilePath задает путь к файлу, параметр ExtendedFileattributes определяет адрес байта памяти, в который будет записано значение байта расширенных атрибутов файла.

Функция возвращает 0 при успешном завершении или код ошибки:

Код ошибки Значение
0xFE У программы нет прав для просмотра каталога
0xFF Файл не найден

Для получения и изменения расширенных атрибутов файла и можно использовать функцию B6h прерывания INT 21h:

На входе: AH = B6h;
AL = Выполняемая функция:
00h - получить байт расширенного атрибута;
01h - изменить байт расширенного атрибута;
DS:DX = Адрес буфера, содержащего путь к файлу;
CL = Новое значение расширенного атрибута.
На выходе: AL = 0, если операция завершилась без ошибок, или
код ошибки:
FCh - нет прав для выполнения функции;
FFh - файл не найден;
CL = Если при вызове функции регистр AL содержал значение 00h, в регистр CL будет записано значение расширенного атрибута указанного файла.

4.3.1. Программа SETEATTR

В программе SETEATTR (листинг 18) мы продемонстрируем использование функции SetExtendedFileAttributes() для изменения байта расширенного атрибута файла, путь к которому указывается в качестве параметра при запуске программы.

// ===================================================
// Листинг 18. Изменение байта расширенных атрибутов
// Файл seteattr\seteattr.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 SetExtendedFileAttributes(char*, BYTE);

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

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

        BYTE NewExtendedFileattributes;
        int ccode;

        printf("\n*SETEATTR* (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("Укажите путь к каталогу и "
                        "устанавливаемый бит (T или I), "
                        "\nнапример: seteattr sys:users\my.dat T");
                return;
        }

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

        strupr(argv[1]);
        strupr(argv[2]);

// Определяем значение байта расширенных атрибутов

        NewExtendedFileattributes = 0x00;

        for(int i = 0; argv[2][i] != '\0' ; i++) {
                switch(argv[2][i]) {
                case 'T':
                        NewExtendedFileattributes |= 0x10; break;
                case 'I':
                        NewExtendedFileattributes |= 0x20; break;
                case '-':
                        NewExtendedFileattributes = 0; break;
                default:
                        printf("Ошибка в параметрах\n");
                        return;
                }
        }

// Изменяем байт расширенных атрибутов

        ccode = SetExtendedFileAttributes(argv[1],
                NewExtendedFileattributes);

        if(!ccode)
                printf("Байт расширенных атрибутов изменен\n");
        else
                printf("Ошибка %02.2X\n", ccode);
}


4.4. Копирование файлов

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

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

int FileServerFileCopy(int FromHandle, int ToHandle,
        long SourceFileOffset, long DestinationFileOffset,
        long NumberOfBytesToCopy, long *BytesCopied);


Параметры FromHandle и ToHandle указывают индексы файлов, участвующих в процессе копирования. Данные копируются из файла, задаваемого параметром FromHandle в файл, задаваемый параметром ToHandle.

Индексы файлов должны быть получены при помощи вызова функции MS-DOS с кодом 3Dh (открыть файл). Если файла, в который будут копироваться данные, нет на диске, его необходимо создать и открыть при помощи функции MS-DOS с кодом 3Ch. В программе, составленной на языке Си, вы можете использовать для открытия и создания файлов функцию open(), входящую в стандартную библиотеку транслятора.

Параметры SourceFileOffset и DestinationFileOffset задают смещение в исходном и выходном файлах. Если вы копируете файл в новый, эти параметры должны иметь нулевое значение.

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

Параметр BytesCopied - указатель на переменную, в которую будет записано количество действительно скопированных байт.

Функция возвращает 0 при успешном завершении или код ошибки:

Код ошибки Значение
0x83 Ошибка ввода/вывода на сетевом диске
0x96 Мало оперативной памяти на файл-сервере

Для копирования файлов можно использовать функцию F3h прерывания INT 21h:

На входе: AH = F3h;
ES:DI = Адрес буфера запроса.
На выходе: AL Код ошибки или 0, если операция завершилась без ошибок;
DX,CX = Количество скопированный байт. Старший байт находится в регистре DX, младший - в регистре CX.

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

struct REQUEST {
        WORD FromHandle;            // индекс входного файла
        WORD ToHandle;              // индекс выходного файла
        long SourceFileOffset;      // смещение входного файла
        long DestinationFileOffset; // смещение выходного файла
        long NumberOfBytesToCopy;   // сколько байт копировать
};


4.4.1. Программа FCOPY

Программа FCOPY (листинг 19) демонстрирует использование функции FileServerFileCopy(). При запуске этой программе необходимо в качестве параметров указать пути к входному и выходному файлам.

// =============================================================
// Листинг 19. Копирование файлов, расположенных на файл-сервере
// Файл fcopy\fcopy.cpp
//
// (C) A. Frolov, 1993
// =============================================================

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <io.h>
#include <sys\stat.h>

extern "C" int GetNetWareShellVersion(char *,char *, char *);
extern "C" int FileServerFileCopy(int, int, long, long, long, long*);

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

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

        int FromHandle;
        int ToHandle;
        long BytesCopied;
        int ccode;

        printf("\n*FCOPY* (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например: fcopy f:\users\my.dat f:\us\my.dat");
                return;
        }
// Параметры должны быть заданы заглавными буквами

        strupr(argv[1]);
        strupr(argv[2]);

// Открываем входной файл в двоичном режиме для чтения

        if ((FromHandle = open(argv[1], O_RDONLY | O_BINARY)) == -1)
        {
                printf("Не могу открыть исходный файл\n");
                return;
        }

// Открываем выходной файл в двоичном режиме для чтения
// и записи, разрешаем создание файла, если его еще нет,
// разрешаем запись в файл

        if ((ToHandle = open(argv[2],
                O_CREAT | O_RDWR | O_BINARY, S_IWRITE)) == -1) {
                printf("Не могу открыть выходной файл\n");
                return;
        }

// Копируем файл, длину файла определяем при помощи
// функции filelength()

        ccode = FileServerFileCopy(FromHandle, ToHandle,
                 0, 0, filelength(FromHandle), &BytesCopied);

        if(!ccode)
                printf("Файл скопирован\n");
        else
                printf("Ошибка %02.2X\n", ccode);

// Закрываем файлы

        close(FromHandle);
        close(ToHandle);
}


4.5. Удаление файлов

Для удаления файлов из сетевых каталогов можно использовать функцию EraseFiles():

int EraseFiles(BYTE DirectoryHandle,
  char *FilePath, BYTE SearchAttributes);


Эта функция удаляет файл, заданный параметрами DirectoryHandle и FilePath, если его атрибуты соответствуют указанным при помощи параметра SearchAttributes. Последнее означает, что, если вы собираетесь стирать нормальные, скрытые и системные файлы, для параметра SearchAttributes необходимо задать значение 06h.

Функция возвращает 0 при успешном завершении или код ошибки:

Код ошибки Значение
0x98 Указанный сетевой том не существует
0x9B Индекс файла указан неправильно
0x9C Путь к файлу указан неправильно
0xFF Файл не найден

4.5.1. Программа FERASE

Программа FERASE (листинг 20) демонстрирует использование функции EraseFiles(). При запуске программе в качестве параметра необходимо передать путь к удаляемому файлу.

// ===================================================
// Листинг 20. Удаление файлов
// Файл ferase\ferase.cpp
//
// (C) A. Frolov, 1993
// ===================================================

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

#define BYTE unsigned char
#define WORD unsigned int

extern "C" int GetNetWareShellVersion(char *,char *, char *);
extern "C" int EraseFiles(BYTE, char*, BYTE);

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

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

        int ccode;

        printf("\n*FERASE* (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("Укажите путь к удаляемому файлу,"
                        "\nнапример: ferase sys:users\my.dat");
                return;
        }

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

        strupr(argv[1]);

        ccode = EraseFiles(0, argv[1], 6);

        if(!ccode)
                printf("Файл %s удален\n", argv[1]);
        else
                printf("Ошибка %02.2X\n", ccode);
}