Guide to Doing File Search Software Development 

                               on NetWare 386




         Table of Contents
         ------------------


         1.0     Introduction

         2.0     File Searching on NetWare
         2.1     File Searches on 286
         2.2     File Searches on 386

         3.0     Software Development Guidelines
         3.1        General Information
         3.2        Using Novel's API
         3.2.1         Coding Examples
         3.3        Using Turbo C
         3.3.1         Coding Examples
         3.4        Using DOS Function Calls
         3.4.1         Coding Examples

         4.0     NCPLIMIT patch for NetWare 386 version 3.10







         1.0     Introduction


         The purpose of this guide is to provide additional information 
         for software developers writing software that will operate on a 
         NetWare environment.  Specifically, this guide addresses problems 
         and guidelines for  doing file and directory searches on NetWare 
         drives.  


         CHAPTER 2:  File searching on NetWare.  This chapter describes
         NetWare file searching under 286 and 386.

         CHAPTER 3:  Software Development Guidelines.  This chapter gives
         specific examples of doing file searches using Novell's API,
         Borland C and DOS function calls.

         CHAPTER 4:  NCPLIMIT patch for NetWare 386 version 3.10.  This
         chapter describes the use of the patch written to fix a problem
         in NetWare.


         Additional References:

            Novell API:  NetWare C Interface.

            BORLAND TURBO C:  Library Reference Guide.

            DOS Technical Reference.





         2.0     File Searching on NetWare


         File searching on NetWare, from a software developers view, is 
         fundamentally the same as doing file searches on DOS.  The real 
         difference being that under DOS, the file searches are performed 
         locally and under NetWare, a file search request command is sent 
         to the File Server and a response is returned when the search is 
         complete.  The NetWare File Server maintains all the directory 
         structures, file structures and tables that are needed to provide 
         directory and file services to all attached workstations.

         A program that performs file searches is any program that does 
         find first's, find next's, or scans directories for file information.
         File searches come in two forms:  1.  when the complete filename or 
         directory name is supplied by the program,  such as "REPORTS.DOC" 
         and  2.  when a wildcard character ( "*" or "?" ) is supplied as a
         part of the filename, such as "MAY??.RPT" or "CLASS*.*".   When a 
         search is done and the complete filename is supplied to NetWare, the
         file server is able to perform the search to completion.  When  a 
         search is done and a wildcard character is supplied, NetWare must 
         retain information about the ongoing search until the searching has
         completed by reaching the end of the specified directory or volume.
         NetWare must  store this information  because the DOS DTA  (Disk 
         Transfer Area) does not have enough space to store a file server 
         number, volume number, and a long (4 byte) search sequence number 
         for over 2 million directory table entries per volume.

         2.1     File Searches on 286


         In order to appreciate how NetWare 386 works it helps to take a 
         look back at NetWare 286 and see how things were.

         Two things to remember about NetWare 286 are first, each work-
         station is running under some version of DOS with the corresponding 
         NetWare shell and second, there is a maximum of 32K  directory 
         table entries per volume.

         Under DOS,  file commands (open, close, search, read, write, etc.)
         typically use a 16 bit file handle to address files and directorys.  
         This 16 bit value worked nicely for addressing the NetWare 286 
         directory table.  NetWare was able to use the information supplied 
         by DOS to perform the file searches.


         2.2     File Searches on 386

         File operations on NetWare 386 are different for a number of 
         reasons.  One of particular interest to file searches exists 
         because of a 386 enhancement allowing for a maximum number of 
         directory table entries per volume of 2,097,152.  With a work-
         station, running DOS, file  handles are still  16 bit values. 
         This 16 bit value is no longer adequate to address all possible
         entries in a NetWare 386 volume directory table.  







         NetWare must now maintain a table of file and directory entries 
         to map the DOS 16 bit handle to a NetWare 32 bit directory index.
         The number of entries in this table is limited by the SET 
         parameter  "Maximum Outstanding  NCP Searches"  (refer to the 
         NetWare 386 System Administration guide for information on the 
         "set" command).  When the number of entries in the table exceeds 
         the maximum, the oldest entry is removed.  If the entry that is 
         removed is still flagged as an "active" entry, the warning message 
         "You exceeded your outstanding  NCP directory search  limit" is 
         displayed on the workstation console.  When this has happened,
         NetWare no longer  has enough information to  complete the file
         search command requested.  A "file not found" status is returned
         to the calling program along with the console message.  This will
         cause any  number of  undesirable side effects  to the software
         involved.  

         The goal of this document is to provide information so developers 
         can write code that does not leave old search information in the
         NetWare search map table.






         3.0     Software Development Guidelines


         3.1        General Information

         This section will attempt to describe correct programming practices 
         when doing file searches under NetWare.

         The problem we are going to try to avoid is starting a file search 
         and leaving it uncompleted.  This will fill  up NetWare's  mapping 
         table with active entries and will eventually produce the warning 
         message described in section 2.2.

         There are  two specific  cases where searches  are started and not 
         completed that will be discussed here.

         Case 1:  A program does a "find first" search using a wildcard
                  character in the file name followed by an "open" on the
                  filename returned by the "find first".  The "find first"
                  search function call will leave an active entry in the 
                  NetWare mapping table.  The correct way to program this 
                  example would be to eliminate the "find first" search 
                  function call.  The "open" function automatically initiates 
                  a file search but does not leave an active entry in the 
                  NetWare search mapping table.

                  NOTE: If the "find first" call did not use wild card
                  characters, it does not cause this problem.

         Case 2:  A program does  a file search in  a given directory using 
                  one of  the wildcard characters  "?" or "*" and  does not 
                  complete the  search.   This happens when a  program is 
                  searching for a file,  finds it, and does not  continue 
                  searching until the end of the directory or volume.  This 
                  will leave an active entry in the  NetWare mapping table 
                  and can eventually produce the warning message described 
                  in section 2.2.

        



         3.2        Using Novel's API

         Novell's API programming library provides two functions that 
         perform directory and file scans and return information about
         the respective directory or file.  "ScanDirectoryInformation" 
         allows a program to obtain information about the first (or next 
         consecutive)  subdirectory of  a specified  directory  and 
         "ScanFileInformation" will perform the same basic function 
         for files.  

         When using these two functions with a wildcard character as a 
         part of the file or directory name search string, the program 
         needs to finish  the search by looping  until the end  of the 
         directory.  Failure to complete the search will leave an active 
         entry in the NetWare mapping table and can eventually produce 
         the warning message described in section 2.2.


         3.2.1         Coding Examples

         /*     Example 1    ScanDirectoryInformation   */

         #include      <nit.h>

         main()
         {
              BYTE         dir_handle;
              int          sequence_number;
              char         sub_dir_name[16];
              BYTE         date_time[4];
              long         owner;
              BYTE         rights_mask;
              int          done;

              /*          .         */
              /*          .         */
              /*          .         */

              sequence_number = 0;         /* find the first subdirectory */
              done = ScanDirectoryInformation( dir_handle,
                                               "*.*", sequence_number,
                                               sub_dir_name, date_time,
                                               &owner, &rights_mask);

              while( !done )               /* loop through all subdirectories */
              {
              /*  process the subdirectory code */
              /*          .                     */
              /*          .                     */
              /*          .                     */
                                           /* get the next subdirectory */
                  done = ScanDirectoryInformation( dir_handle,
                                                   "*.*", sequence_number,
                                                   sub_dir_name, date_time,
                                                   &owner, &rights_mask);
              }
         }




         /*     Example 2    ScanFileInformation   */

         #include      <nit.h>

         main()
         {
              BYTE         dir_handle;
              char         path_name[255];
              char         file_name[15];
              char         creation_date[2];
              char         last_access_date[2];
              char         last_update_date_time[4];
              char         last_archive_date_time[4];
              BYTE         search_attributes;
              BYTE         file_attributes;
              BYTE         ext_file_attributes;
              long         owner;
              long         file_size;
              int          done;


              /*          .         */
              /*          .         */
              /*          .         */

              sequence_number = 0;              /* find the first file */
              done = ScanfileInformation( dir_handle,
                                          path_name, search_attributes,
                                          &sequence_number, file_name,
                                          &file_attributes, 
                                          &ext_file_attributes,
                                          &file_size, creation_date,
                                          last_access_date, 
                                          last_update_date_time,
                                          last_archive_date_time, &owner );

              while( !done )                    /* loop through all files */
              {
              /*  process the next file code    */
              /*          .                     */
              /*          .                     */
              /*          .                     */
                                                /* now get the next file */
                   done = ScanfileInformation( dir_handle,
                                               path_name, search_attributes,
                                               &sequence_number, file_name,
                                               &file_attributes, 
                                               &ext_file_attributes,
                                               &file_size, creation_date,
                                               last_access_date, 
                                               last_update_date_time,
                                               last_archive_date_time, &owner );
              }
         }






         3.3        Using Turbo C

         The Turbo C library contains two function calls that should 
         be used with care when programming for NetWare, "findfirst" 
         and "findnext".  The call "findfirst" should not be used along 
         with any of the Turbo C file open calls.  Any time "findfirst" 
         is used, "findnext" should always be used until searching is 
         complete.


         3.3.1         Coding Examples

         #include      <dir.h>

         main()
         {
              struct ffblk file_find_blk;
              int          done;

              done = findfirst( "*.*",              /* get the first file */
                                &file_find_blk, 0);
              while( !done )                        /* loop through all files */
              {
                 /*  process the file code */
                 /*          ..            */
                 /*          ..            */
                 done = findnext(&file_find_blk);   /* get next file */
              }
         }



         3.4        Using DOS Function Calls

         When using DOS function calls, there are two sets of calls that
         will perform file searches:  Function 17 (11 Hex), Function 18
         (12 Hex) and function 78 (4E Hex), function 79 (4F Hex).  As with
         the previous examples, any time you make a call to function 17 or
         function 78 you  must complete  the searches by using functions 
         18 or 79.  

         It should  also be noted  that functions 17  and 18 are old DOS 
         functions (version  1.0) and  use FCB's  (File Control Blocks) 
         instead of file handles.  Functions 78 and 79 are the recommended 
         functions to use.


         3.4.1         Coding Examples


         file_name     db      "REPORT*.*"

         DTA_buffer    db      43 dup (?)          ;allocate space for the DTA

                       .
                       .
                       .
                                                   ;First we must set up the DTA.
                       mov     ah, 1AH             ;DOS function 1AH
                       mov     dx, seg DTA_buffer  ;ds:dx points to DTA buffer
                       mov     ds, dx
                       mov     dx, offset DTA_buffer
                       int     21H                 ;hand it to DOS
                       .
                       .
                                                   ;Now get ready to search for the
                                                   ;first file...
                       mov     ah, 4EH             ;DOS find first function 
                       mov     cx, 0               ;normal search attribute
                       mov     dx, seg file_name   ;ds:dx points to file name
                       mov     ds, dx
                       mov     dx, offset file_name
                       int     21H                 ;Hand it to DOS
                       jc      no_more_files       ;if carry is set, then no 
                                                   ;file was found.
         file_loop:
                       .                           ;code for processing the
                       .                           ;files as they are found.
                       .
                                                   ;Now setup to find the next
                                                   ;file match
                       mov     ah, 4FH             ;DOS find next file
                       int     21H                 ;Hand it to DOS
                       jc      no_more_files       ;if carry is set, then no 
                                                   ;more files to process

                       jmp     file_loop           ;Always loop until there are 
                                                   ;no more files to process.

         no_more_files:




         4.0     NCPLIMIT patch for NetWare 386 version 3.10


         This patch is written for NetWare 386 version 3.10.  It is to 
         be used with the Novell patch manager NLM "PATCHMAN.NLM".  The 
         "NCPLIMIT.NLM" patch adds code that will provide better manage-
         ment of file searches done on the server.  If you have applications 
         that generate the warning message "You exceeded your outstanding 
         NCP directory search limit." you should load this NLM on the server.

         To load NCPLIMIT.NLM from floppy disk enter the following commands 
         at the server console:


         LOAD A:PATCHMAN            ( This loads the patch manager NLM )
         LOAD A:NCPLIMIT            ( This loads the ncp limit NLM patch )


              
         Using this patch will fix a problem with NetWare management of 
         the  search mapping table but is  NOT a replacement for correct
         programming.  If, after loading this patch, you still get the
         warning message on the workstation, you will need to follow the
         recommendations given in this guide to fix your software.