/*static char *SCCSID = "@(#)fs_fattr.c	6.2 91/01/14";*/
#define SCCSID "@(#)fs_fattr.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_FATTR.C
 *
 *    DESCRIPTION
 *    
 *      Query a file attribute.
 *
 *
 *    FUNCTIONS DEFINED
 *
 *      FS_FILEATTRIBUTE () -   Query a file attribute.
 *
 * 
 *  REVISION HISTORY (in reverse chronological order)
 *  -----------------------------------------------------------------------
 *  2/22/90     Brian Andrew    Modified to simulate HPFS/FAT type response
 *                              when the disk would not need to be modified.
 *                              Return CDROM_WRITE_PROTECT otherwise.
 *  11/14/89    Brian Andrew    Added DBCS support (ParentEndLenDBCS)
 *  10/1/89     Brian Andrew    Added PROBEBUF test for 'pAttr'
 *  9/2/89      Brian Andrew    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 "path.h"
#include "vol.h"
#include "file.h"
#include "buffer.h"
#include "mem.h"
#include "heap.h"
#include "message.h"

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

#include "fsdata.h"
#include "pr_memin.h"
#include "pr_strng.h"
#include "pr_path.h"
#include "pr_dir.h"
#include "pr_misc.h"
#include "pr_dbcs.h"


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



/***    FS_FILEATTRIBUTE () -   Query a file attribute
 *      
 *  DESCRIPTION
 *
 *      We check specifically if the search file is the root directory.
 *      If it is, we pull the attribute out of the root directory entry
 *      in the volume descriptor.
 *
 *      The general case is more complex.  The path name consists of the
 *      full path to the directory containing the file, followed by the
 *      name of the file to search.  The directory containing the search
 *      file is the search directory.
 *
 *      We call 'GetParentDE' to get the DE for the search directory.  This
 *      is the self directory entry from the search directory.
 *
 *      We then call 'FindNextFile' to find the next file in the directory
 *      which matches the search file.  We use a constant which matches any
 *      attribute as a search attribute, and the string following the
 *      search directory in the path name as the search string.
 *      
 *      We only support reading the attribute.  If 'flag' indicates setting      
 *      the attribute we return ERROR_NOT_SUPPORTED.  If the flag isn't    
 *      FA_SET or FA_RETRIEVE we return ERROR_INVALID_PARAMETER.
 *      
 *      
 *  ENTRY
 *
 *      flag        = Flag indicating action to take.  We only support
 *                      0x0000, indicating return information.
 *      pcdfsi      = Pointer to file system independent directory
 *                      information.  Contains the bits indicating if the
 *                      dependent area is vilaid.
 *      pcdfsd      = Pointer to the directory dependent area.  Contains
 *                      the pathe number of the current directory.
 *      pName       = Pointer to the full path name of the desired file.
 *      iCurDirEnd  = Index of the end of the current directory in 'pName'.
 *                      If the current directory is not in the path, this
 *                      value is -1.
 *      pAttr       = Pointer to address to store file attributes.
 *
 *
 *  LOCAL
 *
 *      usRet       = Return value from function.
 *      pdeFirstDE  = Pointer to directory entry struct.  Used during search,
 *                      to store the entry for the parent directory.
 *      pdeThisDE   = Pointer to the DE for the file found.
 *      pvpfsi      = Pointer to the volume independent information.  Not
 *                      used by us.
 *      pvddVolData = Pointer to volume dependent information.  Contains
 *                      the volume descriptor, the path table and the start
 *                      of all the cached sectors for this volume.
 *      cbNameLen   = Used to store the length of pName.
 *      cbBaseOffset = Offset in 'pName' of the last '\' character before
 *                      the target file name.
 *
 *
 *  EXIT
 *
 *      NO_ERROR if search was successful.
 *      ERROR_NOT_SUPPORTED if trying to set attributes.
 *      ERROR_INVALID_PARAMETER if 'type' has invalid parameter.
 *      Return value from FSH_GETVOLPARMS if error.
 *      Return value from GetParentDE if error.
 *      Return value from FindNextFile if error.
 *      Return value from allocation routines if allocation fails.
 */

int far pascal
FS_FILEATTRIBUTE (flag, pcdfsi, pcdfsd, pName, iCurDirEnd, pAttr)
USHORT              flag;
PCDFSI              pcdfsi;
PCDFSD              pcdfsd;
PCHAR               pName;
USHORT              iCurDirEnd;
PUSHORT             pAttr;
{

	USHORT          usRet;
	PDIR_ENTRY      pdeFirstDE;
	PDIR_ENTRY      pdeThisDE;
	PVPFSI          pvpfsi;
	PVOL_DEP_DATA   pvddVolData;
	USHORT          cbNameLen;
	USHORT          cbBaseOffset;

#ifdef DEBUG
	dprintf
	  ("FS_FATTR: flag=%d, Index=%d, Root=%d, Valid=%d, Name=%Fs, Attr=%x\n",
			 flag, iCurDirEnd,
			 pcdfsi->cdi_flags & CDI_ISROOT,
			 pcdfsi->cdi_flags & CDI_ISVALID,
			 pName, *pAttr);
#endif

#ifdef STATS_H
	CurSt.st_fattr++;
#endif

	if (usRet = CHECK_INIT)
		return usRet;

	/* Try to get the volume parameters */
	if (!(usRet = FSH_GETVOLPARM (
							pcdfsi->cdi_hVPB, &pvpfsi,
							(PPVPFSD) &pvddVolData)))
	{
		/*
		*  The following structures are going to be needed
		*
		*    DIR_ENTRY     for the directory entry for the parent
		*                  directory (pdeFirstDE)
		*
		*    DIR_ENTRY     for the directory entry for the path found
		*                  (pdeThisDE)
		*
		*      pdeFirstDE is needed to compute the last sector to search in
		*      for the directory.  ppeThisDE is used to store the information
		*      about the file found.
		*/

		/* Try to allocate the DE struct for thisDE */

		if (!(usRet = GetDirEntry (&pdeThisDE)))
		{

			/* Try to allocate the first extent DIR_ENTRY */

			if (usRet = GetDirEntry (&pdeFirstDE))
			{
#ifdef DEBUG
				dprintf ("\tFS_FATTR:  GetDirEntry  --  %d\n",
					usRet);
#endif
				FREE_DIR_ENTRY (pdeThisDE);

			} /* end if failed first DIR_ENTRY */

		} /* end if get dir entry pdeThisDE */

#ifdef DEBUG
		else /* Else couldn't get the path entry */
		{
			dprintf ("\tFS_FATTR:   GetPathEntry  --  %d\n",
				usRet);
		} /* end else couldn't get ThisDirPE */
#endif

	} /* end if get volume parms */

#ifdef DEBUG                                                                                           
	else
	{
		dprintf ("\tFS_FATTR:  GETVOLPARMS  --  %d\n", usRet);

	}
#endif                                                                                              

	/* Continue looking for a match if no error has occurred */
	if (!usRet)
	{

		cbNameLen = istrlen (pName);

		cbBaseOffset = ParentEndLenDBCS (pName, cbNameLen);

		/*
		 *  We check whether this search file is the root directory.
		 *  If the base offset is one less than the string length.
		 *  In this case, we just copy the root directory attribute.
		 *
		 *  If not retrieving information, we return the correct
		 *  error code.
		 */

		if (cbBaseOffset == (cbNameLen - 1))
		{
			/* Check if attempting to set */
			if (flag & FA_SET)
			{
				usRet = CDROM_WRITE_PROTECT;
			}

			/* Else retrieving information */
			else
			{
				/*  PROBEBUF the user's buffer  */
				if (!(usRet = FSH_PROBEBUF (
									PB_OPWRITE,
									(PCHAR) pAttr,
									sizeof (USHORT))))
				{
					*pAttr = pvddVolData->pdeRootDir->afFileAttr &
								~DOS_ATTR_NEWNAME;

				} /* end if PROBEBUF is successful */

#ifdef DEBUG
				else
				{
					dprintf (
						"\tFS_FATTR:  FSH_PROBEBUF failed  --  %d\n",
						usRet);

				} /* end else PROBEBUF failed */
#endif
			} /* end else retrieving information */

		} /* end if root directory */


		/* Else perform a more in depth search */
		/* Get the directory entry for the directory to search in */

		else if (!(usRet = GetParentDE (
								pvddVolData,
								pcdfsi,
								pdeFirstDE,
								cbBaseOffset,
								pName,
								cbNameLen,
								iCurDirEnd,
								(PDIR_DEP_DATA) pcdfsd)))
		{
			/*
			*  If no errors have occurred, the directory to search
			*  is in pdeFirstDE.
			*
			*  We call FindNextFile with the dir entry for the self DE.
			*
			*  If a match is made we can copy the attribute word
			*  directly.
			*/

			/* Now call FindNext */
			if (!(usRet = FindNextFile (pName + cbBaseOffset + 1,
										ATTR_MATCH_ALL, pdeThisDE,
										pdeFirstDE, TRUE,
										pvddVolData, pcdfsi->cdi_hVPB)))
			{
				/* Check if attempting to set */
				if (flag & FA_SET)
				{
					usRet = CDROM_WRITE_PROTECT;
				}

				/* Else retrieving information */
				else
				{
					/*  PROBEBUF the user's buffer  */
					if (!(usRet = FSH_PROBEBUF (
										PB_OPWRITE,
										(UCHAR FAR *) pAttr,
										sizeof (USHORT))))
					{
						*pAttr = pdeThisDE->afFileAttr &
									(~DOS_ATTR_NEWNAME);

					} /* end if PROBEBUF is successful */

#ifdef DEBUG
					else
					{
						dprintf (
							"\tFS_FATTR:  FSH_PROBEBUF failed  --  %d\n",
							usRet);

					} /* end else PROBEBUF failed */
#endif
				} /* end else retrieving information */

			} /* end if found file */

#ifdef DEBUG                                                                                           
			/* Else couldn't find a match */
			else
			{
				dprintf ("\tFS_FATTR:   FindNextFile  --  %d\n",
						usRet);

			} /* end else couldn't find a match */
#endif                                                                                          

		} /* end if no error, getting parent directory */

#ifdef DEBUG                                                                                           
		/* Else we couldn't find the search directory */
		else
		{
			dprintf ("\tFS_FATTR:  GetParentDE  --  %d\n",
					usRet);

		} /* end else couldn't find the search DE */
#endif                                                                                          

		FREE_DIR_ENTRY (pdeThisDE);

		FREE_DIR_ENTRY (pdeFirstDE);

	} /* end continue looking */

	/* Map the error ERROR_NO_MORE_FILES to ERROR_FILE_NOT_FOUND */
	if (usRet == ERROR_NO_MORE_FILES)
	{
		usRet = ERROR_FILE_NOT_FOUND;
	}

#ifdef DEBUG
	dprintf ("    FS_FATTR: Exit = %d, Attr=%x\n", usRet, *pAttr);
#endif

	return usRet;

	/* no warnings */
	flag; pcdfsi; pcdfsd; pName; iCurDirEnd; pAttr;

}   /* end FS_FILEATTRIBUTE */
