Metropoli BBS
VIEWER: fs_find.c MODE: TEXT (CP437)
//
// $Header: D:/ext2-os2/RCS/fs_find.c,v 1.10 1995/08/16 17:37:15 Willm Exp Willm $
//

// Linux ext2 file system driver for OS/2 2.x and WARP - Allows OS/2 to     
// access your Linux ext2fs partitions as normal drive letters.
// OS/2 implementation : Copyright (C) 1995  Matthieu WILLM
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.



#define INCL_DOS
#define INCL_DOSERRORS
#include <os2.h>		// From the "Developer Connection Device Driver Kit" version 2.0

#include <fsd.h>
#include <fsh.h>

#include <linux/stat.h>
#include <os2/os2proto.h>
#include <os2/os2misc.h>

#include <os2/ifsdbg.h>
#include <os2/filefind.h>
#include <os2/cdfsd.h>
#include <os2/errors.h>

#include <os2/log.h>         /* Prototypes des fonctions de log.c                      */
#include <os2/volume.h>      /* Prototypes des fonctions de volume.c                   */
#include <os2/files.h>       /* Prototypes des fonctions de files.c                    */
#include <linux/fs.h>
#include <linux/fs_proto.h>

#define THISFILE FILE_FS_FIND_C

#define FIL_LEVEL7            7     	// Level 7, return case preserved path name
#define FILE_NONFAT     0x0040		// File is non 8.3 compliant



//
// date_dos2unix  and date_unix2dos are from the Linux FAT file system
//

/* Linear day numbers of the respective 1sts in non-leap years. */

static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
		  /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */


// extern struct timezone sys_tz;


/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */

long date_dos2unix(unsigned short time,unsigned short date)
{
	long month,year,secs;

	month = ((date >> 5) & 15)-1;
	year = date >> 9;
	secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
	    ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
	    month < 2 ? 1 : 0)+3653);
			/* days since 1.1.70 plus 80's leap day */
//	secs += sys_tz.tz_minuteswest*60;
	return secs;
}


/* Convert linear UNIX date to a MS-DOS time/date pair. */

void date_unix2dos(long unix_date,unsigned short _FS_PTR time,
    unsigned short _FS_PTR date)
{
	long day,year,nl_day,month;

//	unix_date -= sys_tz.tz_minuteswest*60;
	*time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
	    (((unix_date/3600) % 24) << 11);
	day = unix_date/86400-3652;
	year = day/365;
	if ((year+3)/4+365*year > day) year--;
	day -= (year+3)/4+365*year;
	if (day == 59 && !(year & 3)) {
		nl_day = day;
		month = 2;
	}
	else {
		nl_day = (year & 3) || day <= 59 ? day : day-1;
		for (month = 0; month < 12; month++)
			if (day_n[month] > nl_day) break;
	}
	*date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
}


/* 1 - means OK, 0 means doesn't match */
int filter_with_attrs(struct inode * pino, unsigned short attrs, pchar name) {
    unsigned short mayhave  = attrs & 0xFF;
    unsigned short musthave = (attrs >> 8) & 0xFF;
    unsigned short mapped;

    mapped = Linux_To_DOS_Attrs(pino, name);


/*
          Actual   May have  Must have  Included   a&may&must ~a&~may&~must a&may&~must  ~a&may&~must
            1          1          1         y           1           0          0               0
            1          1          0         y           0           0          1               0
            1          0          1         n           0           0          0               0
            1          0          0         n           0           0          0               0
            0          1          1         n           0           0          0               0
            0          1          0         y           0           0          0               1
            0          0          1         n           0           0          0               0
            0          0          0         y           0           1          0               0

=> a & may | ~a & ~must

*/

    return !(~(( (mapped &  mayhave) | ( (~mapped) & (~musthave)))));
}

#define TYPEOP_FILEFIND 1
#define TYPEOP_FILEINFO 2

int ino_to_fileinfo(
                    struct inode * pino,
                    pchar databuf, 
                    UINT32 maxlen,
                    PUINT32 plen,
                    unsigned short level,
                    unsigned short flags,
                    unsigned short attrs,
                    struct dirent *pDir,
                    INT32 position, int TypeOp) {
    pCommonFileInfo          pCommon;
    pFileName                pFile;
    PINT32                  pPosition;

    *plen = 0;

    /***************************************************************************/
    /*** First field : long position if FF_GETPOS - nothing if FF_NOPOS      ***/
    /***************************************************************************/
    if (TypeOp == TYPEOP_FILEFIND) {
        if (flags == FF_GETPOS) {
            if (sizeof(INT32) + *plen > maxlen) {
                fs_log("ino_to_fileinfo() - Buffer overflow for first field");
                return ERROR_BUFFER_OVERFLOW;
            }
            pPosition  = (PINT32)(databuf + *plen);
            *pPosition = position;
            *plen += sizeof(INT32);
        }
    }
    /***************************************************************************/

    /***************************************************************************/
    /*** Second field : common file information to all level/flags           ***/
    /***************************************************************************/
    if (sizeof(CommonFileInfo) + *plen > maxlen) {
        kernel_printf("ino_to_fileinfo() - Buffer overflow for second field - len = %lu - maxlen = %lu", (UINT32)sizeof(CommonFileInfo) + (UINT32)(*plen), (UINT32)maxlen);
        return ERROR_BUFFER_OVERFLOW;
    }
    pCommon = (pCommonFileInfo)(databuf + *plen);

    date_unix2dos(pino->i_ctime, &(pCommon->timeCreate), &(pCommon->dateCreate));
    date_unix2dos(pino->i_atime, &(pCommon->timeAccess), &(pCommon->dateAccess));
    date_unix2dos(pino->i_ctime, &(pCommon->timeWrite), &(pCommon->dateWrite));
    pCommon->cbEOF      = pino->i_size;
    pCommon->cbAlloc    = pino->i_blocks;
    pCommon->attr = FILE_NORMAL;

    if ((S_ISLNK(pino->i_mode))  ||
        (S_ISBLK(pino->i_mode))  ||
        (S_ISCHR(pino->i_mode))  ||
        (S_ISFIFO(pino->i_mode)) ||
        (S_ISSOCK(pino->i_mode))) {
        pCommon->attr |= FILE_SYSTEM;     /*** UNIXish special files are seen as SYSTEM files ***/
    } /* endif */

    if (S_ISDIR(pino->i_mode)) {
        pCommon->attr |= FILE_DIRECTORY;
    } /* endif */

    if ((!(pino->i_mode & S_IWUSR)) && 
        (!(pino->i_mode & S_IWGRP)) &&
        (!(pino->i_mode & S_IWOTH))) {
        pCommon->attr |= FILE_READONLY;
    }
    *plen += sizeof(CommonFileInfo);
    /***************************************************************************/

    /***************************************************************************/
    /*** Third field : nothing for level FIL_STANDARD                        ***/
    /***************************************************************************/
    /***************************************************************************/

    /***************************************************************************/
    /*** Third field : Size on disk of EA set for FIL_QUERYEASIZE            ***/
    /***************************************************************************/
    if (level == FIL_QUERYEASIZE) {
        if (sizeof(INT32) + *plen > maxlen) {
            fs_log("ino_to_fileinfo() - Buffer overflow for Third field - FIL_QUERYEASIZE");
            return ERROR_BUFFER_OVERFLOW;
        }
        *((PINT32)(databuf + *plen)) = 0;       /*** No EAS in ext2 ***/
        *plen += sizeof(INT32);
    }
    /***************************************************************************/

    /***************************************************************************/
    /*** Third field : FEAList for level QUERYEASFROMLIST                    ***/
    /***************************************************************************/
    if (level == FIL_QUERYEASFROMLIST) {
        if (sizeof(INT32) + *plen > maxlen) {
            fs_log("ino_to_fileinfo() - Buffer overflow for Third field - FIL_QUERYEASFROMLIST");
            return ERROR_BUFFER_OVERFLOW;
        }
        *((PINT32)(databuf + *plen)) = 4;       /*** No EAS in ext2 ***/ /* this is the length field of FEAList */
        *plen += sizeof(INT32);
    }
    /***************************************************************************/

    /***************************************************************************/
    /*** Fourth field : name                                                 ***/
    /***************************************************************************/
    if (TypeOp == TYPEOP_FILEFIND) {
        if (*plen + sizeof(FileName) + pDir->d_reclen > maxlen) {
            fs_log("ino_to_fileinfo() - Buffer overflow for fourth field");
            return ERROR_BUFFER_OVERFLOW;
        }
        pFile = (pFileName)(databuf + *plen);
        pFile->cbName = (unsigned char)pDir->d_reclen;  /* name length WITHOUT '\0' */
        strcpy(pFile->szName, pDir->d_name);             /* name WITH '\0'           */
        *plen += sizeof(FileName) + pDir->d_reclen; /* sizeof(FileName) + strlen(Dir.d_name) */
    }
    /***************************************************************************/

    return NO_ERROR;
}

int myfindnext(
             struct super_block * p_volume,
             pfile        p_file, 
             unsigned short         attr,
             struct fsfsi   _FS_PTR pfsfsi,
             struct fsfsd   _FS_PTR pfsfsd,
             pchar                  pData,
             unsigned short         cbData,
             unsigned short _FS_PTR pcMatch,
             unsigned short         level,
             unsigned short         flags,
             UINT32                 index_dir,
             int                    is_findfirst,
             id_t                   *pmyid
            ) {
    UINT32 cur_size;
    int    rc;
    struct dirent Dir;
    pchar                    pNom;
    pchar                    pWork, pWorkUpper;
    pchar                    pName, pNameUpper;
    UINT32                   len;
    struct inode *                    ino;
    UINT16 nb_found;

    pName               = ((p_hfind)pfsfsd)->pName;
    pNom                = pName + CCHMAXPATH;
    pWork               = pName + 2 * CCHMAXPATH;
    pNameUpper          = pName + 3 * CCHMAXPATH;
    pWorkUpper          = pName + 4 * CCHMAXPATH;

    nb_found  = 0;
    if (level == FIL_QUERYEASFROMLIST) {
        cur_size = sizeof(EAOP);
    } else {
        cur_size  = 0;
    }

    while (nb_found < *pcMatch) {
        /***********************************************************/
        /*** If we are at the end of the parent dir : stop       ***/
        /***********************************************************/
        if (VFS_readdir(p_file, &Dir) != NO_ERROR) {
            ((p_hfind)pfsfsd)->last = index_dir;
            *pcMatch = nb_found;

            if (nb_found > 0) {
#ifdef FS_TRACE
                kernel_printf("myfindnext()  - EOD - found %d entries", nb_found);
#endif
                return NO_ERROR;
            } else {

#if 1
                if (is_findfirst) {

                    /************************************************************************/
                    /*** Libération du buffer stockant les noms de recherche              ***/
                    /************************************************************************/
                    if ((rc = G_free(((p_hfind)pfsfsd)->pName)) != NO_ERROR) {
                        fs_err(FUNC_FS_FINDFIRST, FUNC_G_free, rc, THISFILE, __LINE__);
                        return rc;
                    } /* end if */
                    /************************************************************************/

                    if ((rc = _close(p_volume, &p_file)) != NO_ERROR) {
                        fs_err(FUNC_FS_FINDFIRST, FUNC_CLOSE, rc, THISFILE, __LINE__);
                        return rc;
                    }
//                    ((p_hfind)pfsfsd)->FS_CLOSEd = SEARCH_ALREADY_CLOSED;
                }
#else           
                    FS_FINDCLOSE(pfsfsi, pfsfsd);
                    ((p_hfind)pfsfsd)->FS_CLOSEd = SEARCH_ALREADY_CLOSED;
#endif
                return ERROR_NO_MORE_FILES;          
            }
        } /* end if */
        /***********************************************************/

        /***********************************************************/
        /*** If we found an entry, see if it matches             ***/
        /***********************************************************/
        strcpy(pWork, pNom);
        strcat(pWork, "\\");
        if (pmyid->pdb != 0) {
            FSH_UPPERCASE(Dir.d_name, strlen(Dir.d_name) + 1, Dir.d_name);
        }
        strcat(pWork, Dir.d_name);
#if 0
#if 1
        if (pmyid->pdb != 0) {
            FSH_UPPERCASE(pName, CCHMAXPATH, pNameUpper);
            FSH_UPPERCASE(pWork, CCHMAXPATH, pWorkUpper);
        } else {
            strcpy(pNameUpper, pName);
            strcpy(pWorkUpper, pWork);
        }
        if (FSH_WILDMATCH(pNameUpper, pWorkUpper) == NO_ERROR) { 
#else
        if (FSH_WILDMATCH(pName, pWork) == NO_ERROR) { 
#endif
#else
        if (FSH_WILDMATCH(pName, pWork) == NO_ERROR) { 
#endif
            if (p_file->f_inode->i_ino != Dir.d_ino) {
                if ((ino = iget(p_volume, Dir.d_ino)) == NULL) {
                    fs_err(FUNC_FS_FINDFIRST, FUNC_GET_VINODE, rc, THISFILE, __LINE__);
                    return ERROR_NO_MORE_FILES;
                } /* endif */
            } else {
                ino = p_file->f_inode;
            }
            if (filter_with_attrs(ino, attr | FILE_READONLY, Dir.d_name)) {
                if ((rc = ino_to_fileinfo(
                                          ino,
                                          pData + cur_size,
                                          cbData - cur_size,
                                          &len,
                                          level,
                                          flags,
                                          attr,
                                          &Dir,
                                          index_dir, TYPEOP_FILEFIND)) != NO_ERROR) {
                    *pcMatch                = nb_found;
                    ((p_hfind)pfsfsd)->last = index_dir;
                    fs_log("====> FS_FINDFIRST : erreur ino_to_fileinfo()");
                    if (p_file->f_inode->i_ino != Dir.d_ino) {
                        iput(ino);
                    }
                    return rc;
                }
                nb_found  ++;
                cur_size += len;
            }
            if (p_file->f_inode->i_ino != Dir.d_ino) {
                iput(ino);
            }
        } /* end if */
        /***********************************************************/

        index_dir ++;
    } /* end while */

    *pcMatch = nb_found;
    ((p_hfind)pfsfsd)->last = index_dir;
#ifdef FS_TRACE
    kernel_printf("myfindnext() - found %d entries", nb_found);
#endif
    return NO_ERROR;

}

/*************************************************************************************************/
/*** FS_FINDFIRST - IFS find first matching file(s) entry point (DosFindFirst API)             ***/
/*************************************************************************************************/
int     _FS_ENTRY FS_FINDFIRST(
                               struct cdfsi   _FS_PTR pcdfsi,
                               struct cdfsd   _FS_PTR pcdfsd,
                               char           _FS_PTR pName,
                               unsigned short         iCurDirEnd,
                               unsigned short         attr,
                               struct fsfsi   _FS_PTR pfsfsi,
                               struct fsfsd   _FS_PTR pfsfsd,
                               char           _FS_PTR pData,
                               unsigned short         cbData,
                               unsigned short _FS_PTR pcMatch,
                               unsigned short         level,
                               unsigned short         flags
                              )
{
    int                      rc;
    UINT32                   openmode = 0;
    pchar                    pNom;
    pfile                    p_file;
    struct super_block *             p_volume;
    id_t                     myid;

#ifdef FS_TRACE
    kernel_printf("FS_FINDFIRST( %s , match = %u , level = %u, flag = %u)", pName, *pcMatch, level, flags);
#endif

    /*******************************************************************/
    /*** Verify we have write access to the user buffer              ***/
    /*******************************************************************/
    if ((rc = FSH_PROBEBUF(PB_OPWRITE, pData, cbData)) != NO_ERROR) {
        fs_err(FUNC_FS_FINDFIRST, FUNC_FSH_PROBEBUF, rc, THISFILE, __LINE__);
        return rc;
    } /* end if */
    /*******************************************************************/

    if ((flags != FF_NOPOS) &&
        (flags != FF_GETPOS)) {
        if ((rc = fs_log("FS_FINDFIRST() - invalid flag")) != NO_ERROR) {
            return rc;
        } /* end if */
        return ERROR_INVALID_PARAMETER;
    }

    if ((level != FIL_STANDARD)    &&
        (level != FIL_QUERYEASIZE) &&
        (level != FIL_QUERYEASFROMLIST)) {
        if ((rc = fs_log("FS_FINDFIRST() - invalid level")) != NO_ERROR) {
            return rc;
        } /* end if */
        return ERROR_INVALID_PARAMETER;
    }

    /*******************************************************************/
    /*** Process identification (to recognize DOS box requests)      ***/
    /*******************************************************************/
    if ((rc = FSH_QSYSINFO(2, (pchar)&myid, sizeof(id_t))) != NO_ERROR) {
        fs_log("erreur FSH_QSYSINFO() dans FS_FINDFIRST");
        return rc;
    }
    if (myid.pdb != 0) {			// DOS Box request => uppercase 
        openmode |= OPENMODE_DOSBOX;
    }
    /*******************************************************************/

    //
    // Gets the superblock
    //
     p_volume = getvolume(pfsfsi->fsi_hVPB);

    //
    // Verify the user asked something !
    //
    if (*pcMatch == 0) {
        fs_log("FS_FINDFIRST - *pcMatch = 0");
        return ERROR_INVALID_PARAMETER;
    } /* end if */

    //
    // Saves the file name to search into pfsfd
    //
    if ((((p_hfind)pfsfsd)->pName = G_malloc(5 * CCHMAXPATH)) == 0) {
        fs_err(FUNC_FS_FINDFIRST, FUNC_G_free, ERROR_NOT_ENOUGH_MEMORY, THISFILE, __LINE__);
        return ERROR_NOT_ENOUGH_MEMORY;
    } /* end if */
    strcpy(((p_hfind)pfsfsd)->pName, pName);
    pNom = ((p_hfind)pfsfsd)->pName + CCHMAXPATH;


    ((p_hfind)pfsfsd)->attr = attr  | FILE_READONLY; /* cf doc : may have Readonly bit never passed */

    //
    // Extracts the parent directory name
    //
    ExtractPath(pName, pNom);

    //
    // Opens the parent directory
    //
    if ((p_file = _open_by_name(p_volume, pNom, openmode | OPENMODE_READONLY)) == 0) {
        fs_err(FUNC_FS_FINDFIRST, FUNC_OPEN_BY_NAME, ERROR_PATH_NOT_FOUND, THISFILE, __LINE__);
        G_free(((p_hfind)pfsfsd)->pName);
        return ERROR_PATH_NOT_FOUND;
    } /* end if */
    ((p_hfind)pfsfsd)->p_file = p_file;



//    ((p_hfind)pfsfsd)->FS_CLOSEd = SEARCH_NOT_CLOSED;

    //
    // Do the actual search
    //
    rc = myfindnext(
                      p_volume,
                      p_file, 
                      attr | FILE_READONLY,
                      pfsfsi,
                      pfsfsd,
                      pData,
                      cbData,
                      pcMatch,
                      level,
                      flags,
                      0,
                      1,
                      &myid
                     );
#ifdef FS_TRACE
    kernel_printf("FS_FINDFIRST - myfindnext returned %d - pcMatch = %d", rc, *pcMatch);
#endif
    return rc;
}
/*************************************************************************************************/

/*************************************************************************************************/
/*** FS_FINDCLOSE - IFS close file search entry point (DosFindClose API)                       ***/
/*************************************************************************************************/
int     _FS_ENTRY FS_FINDCLOSE(
                               struct fsfsi _FS_PTR pfsfsi,
                               struct fsfsd _FS_PTR pfsfsd
                              )
{
    int                  rc;
    struct super_block *         p_volume;

#ifdef FS_TRACE
        kernel_printf("FS_FINDCLOSE( %s )", ((p_hfind)pfsfsd)->pName);
#endif

    //
    // Gets the superblock from pfsfsi
    //
    p_volume = getvolume(pfsfsi->fsi_hVPB);

    //
    // Frees the memory allocated for the search
    //
    if ((rc = G_free(((p_hfind)pfsfsd)->pName)) != NO_ERROR) {
        fs_err(FUNC_FS_FINDCLOSE, FUNC_G_free, rc, FILE_FS_FIND_C, __LINE__);
        return rc;
    } /* end if */


    //
    // Closes the search directory
    //
    if ((rc = _close(p_volume, &(((p_hfind)pfsfsd)->p_file))) != NO_ERROR) {
        fs_err(FUNC_FS_FINDCLOSE, FUNC_CLOSE, rc, FILE_FS_FIND_C, __LINE__);
        return rc;
    }
    return NO_ERROR;
}
/*************************************************************************************************/


/*************************************************************************************************/
/*** FS_FINDFROMNAME - IFS find next matching file(s) entry point (resume by name)             ***/
/*************************************************************************************************/
_FS_RET _FS_ENTRY FS_FINDFROMNAME(
                                  struct fsfsi   _FS_PTR pfsfsi,
                                  struct fsfsd   _FS_PTR pfsfsd,
                                  char           _FS_PTR pData,
                                  unsigned short         cbData,
                                  unsigned short _FS_PTR pcMatch,
                                  unsigned short         level,
                                  unsigned long          position,
                                  char           _FS_PTR pNameFrom,
                                  unsigned short         flags
                                 )
{
    int                      rc;
    struct super_block *             p_volume;
    id_t                     myid;

#ifdef FS_TRACE
    kernel_printf("FS_FINDFROMNAME( %s , match = %u , level = %u, flag = %u)", ((p_hfind)pfsfsd)->pName, *pcMatch, level, flags);
#endif

    //
    // Verify we have write access to the user buffer
    //
    if ((rc = FSH_PROBEBUF(PB_OPWRITE, pData, cbData)) != NO_ERROR) {
        fs_err(FUNC_FS_FINDFROMNAME, FUNC_FSH_PROBEBUF, rc, THISFILE, __LINE__);
        return rc;
    } /* end if */

    if ((flags != FF_NOPOS) &&
        (flags != FF_GETPOS)) {
        if ((rc = kernel_printf("FS_FINDFROMNAME() - invalid flags  : %u", flags)) != NO_ERROR) {
            return rc;
        } /* end if */
        return ERROR_INVALID_PARAMETER;
    }

    if ((level != FIL_STANDARD)    &&
        (level != FIL_QUERYEASIZE) &&
        (level != FIL_QUERYEASFROMLIST)) {
        if ((rc = kernel_printf("FS_FINDFROMNAME() - invalid level  : %u", level)) != NO_ERROR) {
            return rc;
        } /* end if */
        return ERROR_INVALID_PARAMETER;
    }

    /*******************************************************************/
    /*** Process identification (to recognize DOS box requests)      ***/
    /*******************************************************************/
    if ((rc = FSH_QSYSINFO(2, (pchar)&myid, sizeof(id_t))) != NO_ERROR) {
        fs_log("erreur FSH_QSYSINFO() dans FS_FINDFIRST");
        return rc;
    }

    //
    // Gets the superblock from pfsfsi
    //
     p_volume = getvolume(pfsfsi->fsi_hVPB);

    //
    // Verifies the user asked something !
    //
    if (*pcMatch == 0) {
        fs_log("FS_FINDFROMNAME - *pcMatch = 0");
        return ERROR_INVALID_PARAMETER;
    } /* end if */

    //
    // Do the actual search
    //
    return myfindnext(
                      p_volume,
                      ((p_hfind)pfsfsd)->p_file, 
                      ((p_hfind)pfsfsd)->attr,
                      pfsfsi,
                      pfsfsd,
                      pData,
                      cbData,
                      pcMatch,
                      level,
                      flags,
                      ((p_hfind)pfsfsd)->last,
                      0,
                      &myid
                     );


}


/*************************************************************************************************/
/*** FS_FINDNEXT - IFS find next matching file(s) entry point (resume by index)                ***/
/*************************************************************************************************/
int     _FS_ENTRY  FS_FINDNEXT(
                               struct fsfsi   _FS_PTR pfsfsi,
                               struct fsfsd   _FS_PTR pfsfsd,
                               char           _FS_PTR pData,
                               unsigned short         cbData,
                               unsigned short _FS_PTR pcMatch,
                               unsigned short         level,
                               unsigned short         flags
                              )
{
    int                      rc;
    struct super_block *             p_volume;
    id_t                     myid;

#ifdef FS_TRACE
    kernel_printf("FS_FINDNEXT( %s , match = %u , level = %u, flag = %u)", ((p_hfind)pfsfsd)->pName, *pcMatch, level, flags);
#endif

    //
    // Verifies we have write access to the user buffer
    //
    if ((rc = FSH_PROBEBUF(PB_OPWRITE, pData, cbData)) != NO_ERROR) {
        fs_err(FUNC_FS_FINDNEXT, FUNC_FSH_PROBEBUF, rc, THISFILE, __LINE__);
        return rc;
    } /* end if */

    if ((flags != FF_NOPOS) &&
        (flags != FF_GETPOS)) {
        if ((rc = fs_log("FS_FINDNEXT() - invalid flag")) != NO_ERROR) {
            return rc;
        } /* end if */
        return ERROR_INVALID_PARAMETER;
    }

    if ((level != FIL_STANDARD)    &&
        (level != FIL_QUERYEASIZE) &&
        (level != FIL_QUERYEASFROMLIST)) {
        if ((rc = fs_log("FS_FINDNEXT() - invalid level")) != NO_ERROR) {
            return rc;
        } /* end if */
        return ERROR_INVALID_PARAMETER;
    }

    /*******************************************************************/
    /*** Process identification (to recognize DOS box requests)      ***/
    /*******************************************************************/
    if ((rc = FSH_QSYSINFO(2, (pchar)&myid, sizeof(id_t))) != NO_ERROR) {
        fs_log("erreur FSH_QSYSINFO() dans FS_FINDFIRST");
        return rc;
    }

    //
    // Gets the superblock from pfsfsi
    //
     p_volume = getvolume(pfsfsi->fsi_hVPB);

    //
    // Verifies the user asked something !
    //
    if (*pcMatch == 0) {
        fs_log("FS_FINDNEXT - *pcMatch = 0");
        return ERROR_INVALID_PARAMETER;
    } /* end if */

    //
    // Do the actual search
    //
    return myfindnext(
                      p_volume,
                      ((p_hfind)pfsfsd)->p_file, 
                      ((p_hfind)pfsfsd)->attr,
                      pfsfsi,
                      pfsfsd,
                      pData,
                      cbData,
                      pcMatch,
                      level,
                      flags,
                      ((p_hfind)pfsfsd)->last,
                      0,
                      &myid
                     );


}
/*************************************************************************************************/



_FS_RET _FS_ENTRY FS_FILEINFO(
                              unsigned short         flag,
                              struct sffsi   _FS_PTR psffsi,
                              struct sffsd   _FS_PTR psffsd,
                              unsigned short         level,
                              char           _FS_PTR pData,
                              unsigned short         cbData,
                              unsigned short         IOflag
                             )
{
    int     rc;
    UINT32  len;
    pfile   p_file;
    struct super_block * p_volume;
    PEAOP   peaop;


    if ((level != FIL_STANDARD)         &&
        (level != FIL_QUERYEASIZE)      &&
        (level != FIL_QUERYEASFROMLIST) &&
        (level != FIL_QUERYALLEAS)      && // Undocumented level - similar to level 3 but for full EA set
        (level != FIL_LEVEL7)) {
        if ((rc = kernel_printf("FS_FILEINFO() - invalid level %u", level)) != NO_ERROR) {
            return rc;
        } /* end if */
        return ERROR_INVALID_PARAMETER;
    }

    //
    // Get the superblock from psffsi
    //
    p_volume = getvolume(psffsi->sfi_hVPB);

    //
    // Gets the file structure from psffsd
    //
    p_file = ((_sffsd _FS_PTR)psffsd)->p_file;

    switch(flag) {
        case FI_SET :
#ifdef FS_TRACE
            kernel_printf("FS_FILEINFO( FI_SET )");
#endif
            if (Read_Write) {
                // We should do something here !
                return NO_ERROR;
            } else {
                return ERROR_WRITE_PROTECT;
            }

        case FI_RETRIEVE :
#ifdef FS_TRACE
            if ((rc = kernel_printf("FS_FILEINFO(FI_RETRIEVE - lvl = %u - inode %lu )", level, p_file->f_inode->i_ino)) != NO_ERROR) {
                return rc;
            } /* end if */
#endif
            //
            // Verify we have write access to the user buffer
            //
            if ((rc = FSH_PROBEBUF(PB_OPWRITE, pData, cbData)) != NO_ERROR) {
                fs_err(FUNC_FS_FILEINFO, FUNC_FSH_PROBEBUF, rc, THISFILE, __LINE__);
                return rc;
            } /* end if */

            if ((level == FIL_QUERYEASFROMLIST) ||
                (level == FIL_QUERYALLEAS)) {
                peaop = (PEAOP)pData;
                if ((rc = FSH_PROBEBUF(PB_OPWRITE, (pchar)peaop, 4)) != NO_ERROR) {
                    fs_err(FUNC_FS_FILEINFO, FUNC_FSH_PROBEBUF, rc, THISFILE, __LINE__);
                    return rc;
                } /* end if */
                peaop->fpFEAList->cbList = 4;
            } else {
            if ((rc = ino_to_fileinfo(
                                      p_file->f_inode,
                                      pData, 
                                      cbData,
                                      &len,
                                      level,
                                      0,
                                      0,
                                      0,
                                      0, TYPEOP_FILEINFO)) != NO_ERROR) {
                fs_log("FS_FILEINFO() - ino_to_fileinfo()");
                return rc;
            }
            }
            break;
        default :
            fs_log("FS_FILEINFO() - Unknown flag");
            return ERROR_INVALID_PARAMETER;
    }             
    return NO_ERROR;
}




_FS_RET _FS_ENTRY FS_PATHINFO(
                              unsigned short         flag,
                              struct cdfsi   _FS_PTR pcdfsi,
                              struct cdfsd   _FS_PTR pcdfsd,
                              char           _FS_PTR pName,
                              unsigned short         iCurDirEnd,
                              unsigned short         level,
                              char           _FS_PTR pData,
                              unsigned short         cbData
                             )
{
    int      rc, rc3;
    struct super_block *  p_volume;
    pfile    p_file;
    UINT32   len, openmode = 0;
    PEAOP    peaop;
    id_t     myid;

    //
    // Verify the level is valid
    //
    if ((level != FIL_STANDARD)         &&
        (level != FIL_QUERYEASIZE)      &&
        (level != FIL_QUERYEASFROMLIST) &&
        (level != FIL_QUERYALLEAS)      &&  // Undocumented level - similar to level 3 but for full EA set
        (level != FIL_LEVEL7)) {
        kernel_printf("FS_PATHINFO() - invalid level %u", level);
        return ERROR_INVALID_PARAMETER;
    }

    /*******************************************************************/
    /*** Process identification (to recognize DOS box requests)      ***/
    /*******************************************************************/
    if ((rc = FSH_QSYSINFO(2, (pchar)&myid, sizeof(id_t))) != NO_ERROR) {
        fs_log("erreur FSH_QSYSINFO() dans FS_FINDFIRST");
        return rc;
    }
    if (myid.pdb != 0) {
        openmode = OPENMODE_DOSBOX;
    }

    //
    // Retrieves the superblock from psffsi
    //
    p_volume = getvolume(pcdfsi->cdi_hVPB);

    switch(flag) {
        case PI_RETRIEVE :
#ifdef FS_TRACE
            if ((rc = kernel_printf("FS_PATHINFO(PI_RETRIEVE - lvl = %u - %s )", level, pName)) != NO_ERROR) {
                return rc;
            } /* end if */
#endif
            //
            // Verify we have write access to the user buffer
            //
            if ((rc = FSH_PROBEBUF(PB_OPWRITE, pData, cbData)) != NO_ERROR) {
                fs_err(FUNC_FS_PATHINFO, FUNC_FSH_PROBEBUF, rc, THISFILE, __LINE__);
                return rc;
            } /* end if */

            switch(level) {
                case FIL_LEVEL7 :
                    if (strlen(pName) + 1 > cbData) {
                        return ERROR_BUFFER_OVERFLOW;
                    }
                    memcpy(pData, pName,strlen(pName) + 1);
                    return NO_ERROR;

                default :
                    if ((p_file = _open_by_name(p_volume, pName, openmode | OPENMODE_READONLY)) == 0) {
#ifdef FS_TRACE
                        fs_err(FUNC_FS_PATHINFO, FUNC_OPEN_BY_NAME, ERROR_PATH_NOT_FOUND, THISFILE, __LINE__);
#endif
                        return ERROR_FILE_NOT_FOUND;
                    }

            if ((level == FIL_QUERYEASFROMLIST) ||
                (level == FIL_QUERYALLEAS)) {
                peaop                    = (PEAOP)pData;
                if ((rc = FSH_PROBEBUF(PB_OPWRITE, (pchar)peaop, 4)) != NO_ERROR) {
                    fs_err(FUNC_FS_PATHINFO, FUNC_FSH_PROBEBUF, rc, THISFILE, __LINE__);
                    return rc;
                } /* end if */
                peaop->fpFEAList->cbList = 4;       // NO EAS for ext2
            } else {
                    if ((rc = ino_to_fileinfo(
                                              p_file->f_inode,
                                              pData, 
                                              cbData,
                                              &len,
                                              level,
                                              0,
                                              0,
                                              0,
                                              0, TYPEOP_FILEINFO)) != NO_ERROR) {
                        fs_log("FS_PATHINFO() - ino_to_fileinfo()");
                        if ((rc3 = _close(p_volume, &p_file)) != NO_ERROR) {
                            fs_err(FUNC_FS_PATHINFO, FUNC_CLOSE, rc3, THISFILE, __LINE__);
                        }
                        return rc;
                    }
                    }
                    if ((rc = _close(p_volume, &p_file)) != NO_ERROR) {
                        fs_err(FUNC_FS_PATHINFO, FUNC_CLOSE, rc, THISFILE, __LINE__);
                        return rc;
                    }
                    return NO_ERROR;
            }
            break;

        case PI_SET :
        case PI_SET + 0x10 :
#ifdef FS_TRACE
            if ((rc = kernel_printf("FS_PATHINFO(PI_SET - %s )", pName)) != NO_ERROR) {
                return rc;
            } /* end if */
#endif
            if (Read_Write) {
                // We should do something here !
                return NO_ERROR;
            } else {
                return ERROR_WRITE_PROTECT;
            }


        default :
            if ((rc = kernel_printf("FS_PATHINFO( %s ) - unknown flag %d", pName, flag)) != NO_ERROR) {
                return rc;
            } /* end if */
            return ERROR_INVALID_PARAMETER;

    } /* end switch */

}
[ RETURN TO DIRECTORY ]