/*static char *SCCSID = "@(#)fs_ffrom.c 6.2 91/01/14";*/
#define SCCSID "@(#)fs_ffrom.c  6.2 91/01/14"
/*
 *      IBM/Microsoft Confidential
 *
 *      Copyright (c) IBM Corporation 1987, 1989
 *      Copyright (c) Microsoft Corporation 1987, 1989
 *
 *      All Rights Reserved
 *
 */

/*
 *  FS_FFROM.C
 *
 *    DESCRIPTION
 *
 *      Find matching file starting from name.
 *
 *    FUNCTIONS DEFINED
 *
 *      FS_FINDFROMNAME
 *
 *
 *  REVISION HISTORY (in reverse chronological order)
 *  -----------------------------------------------------------------------
 *  1/19/94     Doug Barra      @DB65536 -Implement Backing up a search if
 *                              the requested file is not the next file
 *  9/13/89     Paul Bingman    First working version
 *  8/4/89      Brian Andrew    Initial Blank Template
 *
 *
 *  TO DO
 *  -------------------------------------------------------------------------
 *
 */

#define INCL_DOSERRORS
#define INCL_NOPMAPI
#include <os2.h>
#include <fsd.h>
#include <fsh.h>

#include "cdfs.h"
#include "sem.h"
#include "vol.h"
#include "path.h"
#include "file.h"
#include "buffer.h"
#include "mem.h"
#include "heap.h"
#include "message.h"
#include "pr_dir.h"

#ifdef STATS_H
#include "stats.h"
#endif

#include "fsdata.h"
#include "pr_memin.h"
#include "pr_file.h"
#include "memory.h"

#ifdef DEBUG
#include "pr_DEBUG.h"
#endif



int far pascal
FS_FINDFROMNAME (
        PFSFSI      pfsfsi,
        PFSFSD      pfsfsd,
        PCHAR       pbData,     /* ptr to data buffer */
        USHORT      cbData,     /* size of data buffer */
        PUSHORT     pcMatch,    /* number of matching entries returned */
        USHORT      usLevel,    /* level of info returned */
        ULONG       ulPos,      /* unused by LPFS */
        PCHAR       pbName,
        USHORT      usFlags)
{
/*
 * @DB65536 - Inserted code from FS_FINDNEXT and modified
 */
  PVPFSI        pvpfsi;
  PVOL_DEP_DATA pvddVolData;
  PDIR_ENTRY    pdeTempDE;
  PDIR_ENTRY    pdeThisDE;
  PDIR_ENTRY    pdePrevDE;
  BOOL          FirstMatch = TRUE;
  USHORT        usMatchesLeft;
  USHORT        cbDataSize;
  USHORT        usRet;
  PCHAR         pbDataStart;

#ifdef DEBUG
  dprintf ("FS_FFROM: Level %d, Flags %d, Match=%d, Name=%Fs\n", usLevel, usFlags,*pcMatch,pbName);
#endif


  /*
   *  We check to see if a close has started or if someone else is using
   *  the directory entry.  If a close has started, we exit returning
   *  ERROR_FILE_NOT_FOUND.  If someone else is using the search
   *  work area, we wait for a semaphore to clear.
   */

#ifdef STATS_H
  CurSt.st_fnext++;
#endif

  /*
   * Get a copy of the start of the buffer and save.
   * This will be used by the level 3 code.
   */

  pbDataStart = pbData;

  /* Initialize the return values */
  usMatchesLeft = *pcMatch;
  *pcMatch = 0;

  /* Check for initialization */
  if (usRet = CHECK_INIT)
    return usRet;

  /*
   *  We perform the necessary structure allocations and obtain the
   *  the volume structures.
   */
  if (!(usRet = FSH_GETVOLPARM (  pfsfsi->fsi_hVPB, &pvpfsi,
                  (PPVPFSD) &pvddVolData)))
  {
    /* Get the DE structure for the current DE */
    if (!(usRet = GetDirEntry (&pdeThisDE)))
    {
      /* Get the DE structure for previous DE */
      if (!(usRet = GetDirEntry (&pdePrevDE)))
      {
        /* Wait on the search semaphore */
        SEM_REQ (((PSEARCH_DEP_DATA) pfsfsd)->sSearchSem);

        /* Check if a close has started */
        if (!((PSEARCH_DEP_DATA) pfsfsd)->fSearchClose)
        {
          /* Register as a reader */
          ((PSEARCH_DEP_DATA) pfsfsd)->usCountSearch++;

          *pdePrevDE = *((PSEARCH_DEP_DATA) pfsfsd)->pdeLastDir;

          /* Give up the semaphore */
          SEM_CLEAR (((PSEARCH_DEP_DATA) pfsfsd)->sSearchSem);

          /*
           *  If no errors have occurred we are ready to look for
           *  matches.
           *  The search will end on three conditions
           *
           *      1) We have found all the matches asked for.
           *
           *      2) We have a match, but can't fit the data in the users
           *   area.
           *
           *      3) We couldn't get all the matches requested.
           *
           *  There is some doubt about what constitutes an error
           *  for FINDNEXT.  We will return an error on the
           *  following conditions.
           *
           *      1) Couldn't find as many files as requested
           *   (although the number of files found will be
           *   returned).
           *
           *      2) Ran out of buffer space before ran out of file
           *   matches (although the number of buffers found
           *   is returned).
           *
           *  We will always save the last file directory entry
           *  found in the search dependent work to continue the
           *  search.
           */


          /*
           *  Basic algorithm
           *
           *      While not all users matches requested not found
           *
           *    If find another match
           *
           *        If the data fits into the data area
           *
           *      Store the data in the area
           *      Decrement the space left in the area
           *      Increment the number of matches made
           *      Swap the last file found into search area
           *
           *        Else Break
           *
           *    Else Break
           */
          while (usMatchesLeft--)
          {
            /*
             *  We check to see if we are searching for the root directory.
             *  If we are, there are two possibilities
             *
             *      1) We have not returned the root directory
             *
             *      2) We have returned the root.
             *
             *  In the first case we store the root directory information
             *  in 'pdeNextDE' and set the 'fRetRootDir' flag.
             *
             *  In the second case we set usRet to ERROR_NO_MORE FILES
             *
             *  If we are not looking for the root directory, we use the
             *  directory entry in the search dependent data as a starting
             *  point to search for a match.
             */

            /* Wait on the search semaphore */
            SEM_REQ (((PSEARCH_DEP_DATA) pfsfsd)->sSearchSem);

            if (((PSEARCH_DEP_DATA) pfsfsd)->fRootDir)
            {
              /* Check if we have already returned the directory */
              if(((PSEARCH_DEP_DATA) pfsfsd)->fRetRootDir)
              {
                usRet = ERROR_NO_MORE_FILES;

              } /* end if already returned */

              /*
               *  Else copy the root dir into pdeThisDE and set the
               *  the fRetRootDir flag.
               */
              else
              {

                *pdeThisDE = *(pvddVolData->pdeRootDir);

                ((PSEARCH_DEP_DATA) pfsfsd)->fRetRootDir = TRUE;

              } /* end if use previous DE */

            } /* end if search for root directory */

            /* Else use the existing directory as a start point */
            else
            {
              usRet = FindNextFile (
                    ((PSEARCH_DEP_DATA) pfsfsd)->pssSearchString->szName,
                    ((PSEARCH_DEP_DATA) pfsfsd)->afAttr,
                    pdeThisDE,
                    pdePrevDE,
                    ((PSEARCH_DEP_DATA) pfsfsd)->fFirstSearch,
                    pvddVolData,
                    pfsfsi->fsi_hVPB);

              ((PSEARCH_DEP_DATA) pfsfsd)->fFirstSearch = FALSE;

            } /* end else use previous directory */

            /* Give up the semaphore */
            SEM_CLEAR (((PSEARCH_DEP_DATA) pfsfsd)->sSearchSem);

            /*
             * @DB65536 - Start of modifications
             */
            if (FirstMatch)
            { /* Is this the first file we looked for? */
              if (StrnCmpDBCS(pdePrevDE->szFileID,pbName,strlen(pbName)) != 0)
              { /* Was the previous file the right one? */
                /* We have been requested to backup the search! We need to */
                /* search from the top of the list for the requested name. */

                /* Wait on the search semaphore */
                SEM_REQ (((PSEARCH_DEP_DATA) pfsfsd)->sSearchSem);

                /* Start at the top of the directory list */
                ((PSEARCH_DEP_DATA) pfsfsd)->fFirstSearch = TRUE;
                *pdeThisDE = *((PSEARCH_DEP_DATA) pfsfsd)->pdeParentDir;

                do
                {
                  /* Find the next entry in the list */
                  *pdePrevDE = *pdeThisDE;
                  usRet = FindNextFile (
                        ((PSEARCH_DEP_DATA) pfsfsd)->pssSearchString->szName,
                        ((PSEARCH_DEP_DATA) pfsfsd)->afAttr,
                        pdeThisDE,
                        pdePrevDE,
                        ((PSEARCH_DEP_DATA) pfsfsd)->fFirstSearch,
                        pvddVolData,
                        pfsfsi->fsi_hVPB);

                  ((PSEARCH_DEP_DATA) pfsfsd)->fFirstSearch = FALSE;

                  /* Search until end of list or entry found */
                } while (!usRet && (strncmpDBCS(pdePrevDE->szFileID,pbName,strlen(pbName)) != 0));

                /* update search record to indicate the new location */
                *((PSEARCH_DEP_DATA) pfsfsd)->pdeLastDir = *pdeThisDE;

                /* Give up the semaphore */
                SEM_CLEAR (((PSEARCH_DEP_DATA) pfsfsd)->sSearchSem);
              } /* end if right file */
              FirstMatch = FALSE;
            } /* end if firstmatch */
            /*
             * @DB65536 - End of modifications
             */

            /*
             *  If there are no errors, the matching file is in
             *  pdeThisDE.  We look to see if the returned data
             *  will fit.
             */

            if (!usRet)
            {
              /* Check if the data will fit */
              if (!(usRet = FNextInfoFit (
                      pbDataStart,
                      pbData, cbData, usLevel,
                      usFlags, pdeThisDE,
                      pvddVolData->pvdVolDesc->cbLogBlk,
                      &cbDataSize,
                      ((PSEARCH_DEP_DATA) pfsfsd)->afAttr)))
                /*
                 *  'pdeNextDE' contains the data on the next
                 *  file, it's possible with EA support that
                 *  we will have to hit the disk to find out
                 *  about EA's.  The directory entry has the
                 *  location and length of the XAR.
                 *
                 *  FSH_PROBEBUF uses
                 *  ERROR_PROTECTION_VIOLATION as its return
                 *  value when invalid access, if you
                 *  want to do the same.
                 *
                 *  For 'usFlags' = 1, we always leave the
                 *  'position' field blank.
                 */
              {
                /*
                 *  Increment the pointer into the user's
                 *  area by the amount of data transfered,
                 *  then decrement the amount left for the
                 *  users
                 *
                 *      pbData += DataSize;
                 *      cbData -= DataSize; (remember cbData
                 *        is unsigned
                 *        don't let it go
                 *        below zero)
                 */
                pbData += cbDataSize;
                cbData -= cbDataSize;

                /* Wait on the search semaphore */
                SEM_REQ (((PSEARCH_DEP_DATA) pfsfsd)->sSearchSem);

                *((PSEARCH_DEP_DATA) pfsfsd)->pdeLastDir =
                                  *pdeThisDE;

                /* Give up the semaphore */
                SEM_CLEAR (((PSEARCH_DEP_DATA) pfsfsd)->sSearchSem);

                /* Increment matches made */

                (*pcMatch)++;

              } /* end if data fits in the data area */

              /* Else we exit */
              else
              {
#ifdef DEBUG
                dprintf ("\tFS_FFROM:  FNextInfoFit  --  %d\n",
                    usRet);
#endif
                break;

              } /* else data didn't fit */

            } /* end if found another match */

            /* Else break out of while loop */
            else
            {
              break;
            }

            /* Move to the next DE */
            pdeTempDE = pdeThisDE;
            pdeThisDE = pdePrevDE;
            pdePrevDE = pdeTempDE;

          } /* end while more matches */

          /* Clean up the search dependent area */
          /* Wait on the search semaphore */
          SEM_REQ (((PSEARCH_DEP_DATA) pfsfsd)->sSearchSem);

          /* Exit as a searcher */
          ((PSEARCH_DEP_DATA) pfsfsd)->usCountSearch--;

          /* Give up the semaphore */
          SEM_CLEAR (((PSEARCH_DEP_DATA) pfsfsd)->sSearchSem);

        } /* end if close has not started */

        /* Else return invalid access */
        else
        {
          usRet = ERROR_FILE_NOT_FOUND;

          SEM_CLEAR (((PSEARCH_DEP_DATA) pfsfsd)->sSearchSem);

        }


        FREE_DIR_ENTRY (pdePrevDE);

      } /* end if successful DE allocation for PrevDE */

#ifdef DEBUG
      /* Else print error message */
      else
      {
        dprintf ("\tFS_FINDNEXT:  GetDirEntry (PrevDE)  %d\n", usRet);
      }
#endif

      /* Give up this DE */
      FREE_DIR_ENTRY (pdeThisDE);

    } /* end if successful DE allocation for ThisDE */

#ifdef DEBUG
    /* Else print error message */
    else
    {
      dprintf ("\tFS_FINDNEXT:  GetDirEntry (ThisDE)  %d\n", usRet);
    }
#endif

  } /* end if volume parameters obtained */

#ifdef DEBUG
  /* Else print error message */
  else
  {

    dprintf ("\tFS_FINDNEXT:  GETVOLPARM  --  %d\n", usRet);
  }
#endif

  /*
   *  We check in the case where multiple files were being searched for.
   *  If we found at least one file, we don't return NO_MORE_FILES.
   */

  if ((usRet) && (usRet != ERROR_EAS_DIDNT_FIT) && (*pcMatch))
  {
    usRet = NO_ERROR;

  }

#ifdef DEBUG
  dprintf ("    FS_FFROM:  Exit  --  %d, Matches  --  %d\n", usRet, *pcMatch);

#endif


  return usRet;

  /* No warnings */
  usLevel; usFlags;

/*
 * @DB65536 - End of Insertion.
 */

}   /* end FS_FINDFROMNAME */
