Skip to content
Snippets Groups Projects
dos_fs.c 80.4 KiB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
 */
HANDLE WINAPI FindFirstFileA(
	LPCSTR lpFileName,
	WIN32_FIND_DATAA *lpFindData )
Alexandre Julliard's avatar
Alexandre Julliard committed
{
    return FindFirstFileExA(lpFileName, FindExInfoStandard, lpFindData,
                            FindExSearchNameMatch, NULL, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
}

/*************************************************************************
 *           FindFirstFileExA   (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
 */
HANDLE WINAPI FindFirstFileExA(
	LPCSTR lpFileName,
	FINDEX_INFO_LEVELS fInfoLevelId,
	LPVOID lpFindFileData,
	FINDEX_SEARCH_OPS fSearchOp,
	LPVOID lpSearchFilter,
	DWORD dwAdditionalFlags)
Alexandre Julliard's avatar
Alexandre Julliard committed
{
    WIN32_FIND_DATAA *dataA;
    WIN32_FIND_DATAW dataW;
    UNICODE_STRING pathW;
        SetLastError(ERROR_PATH_NOT_FOUND);
        return INVALID_HANDLE_VALUE;
    if (!RtlCreateUnicodeStringFromAsciiz(&pathW, lpFileName))
Alexandre Julliard's avatar
Alexandre Julliard committed
    {
        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
        return INVALID_HANDLE_VALUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
    }

    handle = FindFirstFileExW(pathW.Buffer, fInfoLevelId, &dataW, fSearchOp, lpSearchFilter, dwAdditionalFlags);
    RtlFreeUnicodeString(&pathW);
    if (handle == INVALID_HANDLE_VALUE) return handle;

    dataA = (WIN32_FIND_DATAA *) lpFindFileData;
    dataA->dwFileAttributes = dataW.dwFileAttributes;
    dataA->ftCreationTime   = dataW.ftCreationTime;
    dataA->ftLastAccessTime = dataW.ftLastAccessTime;
    dataA->ftLastWriteTime  = dataW.ftLastWriteTime;
    dataA->nFileSizeHigh    = dataW.nFileSizeHigh;
    dataA->nFileSizeLow     = dataW.nFileSizeLow;
    WideCharToMultiByte( CP_ACP, 0, dataW.cFileName, -1,
                         dataA->cFileName, sizeof(dataA->cFileName), NULL, NULL );
    WideCharToMultiByte( CP_ACP, 0, dataW.cAlternateFileName, -1,
                         dataA->cAlternateFileName, sizeof(dataA->cAlternateFileName), NULL, NULL );
Alexandre Julliard's avatar
Alexandre Julliard committed
    return handle;
}

/*************************************************************************
 *           FindFirstFileW   (KERNEL32.@)
 */
HANDLE WINAPI FindFirstFileW( LPCWSTR lpFileName, WIN32_FIND_DATAW *lpFindData )
{
    return FindFirstFileExW(lpFileName, FindExInfoStandard, lpFindData,
                            FindExSearchNameMatch, NULL, 0);
}
Alexandre Julliard's avatar
Alexandre Julliard committed

/*************************************************************************
 *           FindNextFileW   (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
 */
BOOL WINAPI FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *data )
Alexandre Julliard's avatar
Alexandre Julliard committed
{
    FIND_FIRST_INFO *info;
    DWORD gle = ERROR_NO_MORE_FILES;
    if ((handle == INVALID_HANDLE_VALUE) ||
       !(info = (FIND_FIRST_INFO *)GlobalLock( handle )))
Alexandre Julliard's avatar
Alexandre Julliard committed
    {
        SetLastError( ERROR_INVALID_HANDLE );
Alexandre Julliard's avatar
Alexandre Julliard committed
    }
    if (info->drive == -1)
    {
        ret = SMB_FindNext( info->u.smb_dir, data );
        if(!ret)
        {
            SMB_CloseDir( info->u.smb_dir );
            HeapFree( GetProcessHeap(), 0, info->path );
        }
        goto done;
    }
    else if (!info->path || !info->u.dos_dir)
Alexandre Julliard's avatar
Alexandre Julliard committed
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
    }
    else if (!DOSFS_FindNextEx( info, data ))
Alexandre Julliard's avatar
Alexandre Julliard committed
    {
        DOSFS_CloseDir( info->u.dos_dir ); info->u.dos_dir = NULL;
        HeapFree( GetProcessHeap(), 0, info->path );
        info->path = NULL;
        HeapFree( GetProcessHeap(), 0, info->long_mask );
        info->long_mask = NULL;
        goto done;
Alexandre Julliard's avatar
Alexandre Julliard committed
    }
    if( !ret ) SetLastError( gle );
Alexandre Julliard's avatar
Alexandre Julliard committed
}


/*************************************************************************
 *           FindNextFileA   (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
 */
BOOL WINAPI FindNextFileA( HANDLE handle, WIN32_FIND_DATAA *data )
Alexandre Julliard's avatar
Alexandre Julliard committed
{
    WIN32_FIND_DATAW dataW;
    if (!FindNextFileW( handle, &dataW )) return FALSE;
    data->dwFileAttributes = dataW.dwFileAttributes;
    data->ftCreationTime   = dataW.ftCreationTime;
    data->ftLastAccessTime = dataW.ftLastAccessTime;
    data->ftLastWriteTime  = dataW.ftLastWriteTime;
    data->nFileSizeHigh    = dataW.nFileSizeHigh;
    data->nFileSizeLow     = dataW.nFileSizeLow;
    WideCharToMultiByte( CP_ACP, 0, dataW.cFileName, -1,
                         data->cFileName, sizeof(data->cFileName), NULL, NULL );
    WideCharToMultiByte( CP_ACP, 0, dataW.cAlternateFileName, -1,
                         sizeof(data->cAlternateFileName), NULL, NULL );
Alexandre Julliard's avatar
Alexandre Julliard committed
    return TRUE;
}

/*************************************************************************
 *           FindClose   (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
 */
BOOL WINAPI FindClose( HANDLE handle )
Alexandre Julliard's avatar
Alexandre Julliard committed
{
    FIND_FIRST_INFO *info;

    if (handle == INVALID_HANDLE_VALUE) goto error;

        if ((info = (FIND_FIRST_INFO *)GlobalLock( handle )))
        {
            if (info->u.dos_dir) DOSFS_CloseDir( info->u.dos_dir );
            if (info->path) HeapFree( GetProcessHeap(), 0, info->path );
            if (info->long_mask) HeapFree( GetProcessHeap(), 0, info->long_mask );
    }
    __EXCEPT(page_fault)
    {
        WARN("Illegal handle %p\n", handle);
        SetLastError( ERROR_INVALID_HANDLE );
        return FALSE;
    }
    __ENDTRY
    GlobalUnlock( handle );
    GlobalFree( handle );
Alexandre Julliard's avatar
Alexandre Julliard committed
    return TRUE;

 error:
    SetLastError( ERROR_INVALID_HANDLE );
    return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
 *           DOSFS_UnixTimeToFileTime
 *
 * Convert a Unix time to FILETIME format.
 * The FILETIME structure is a 64-bit value representing the number of
Alexandre Julliard's avatar
Alexandre Julliard committed
 * 100-nanosecond intervals since January 1, 1601, 0:00.
 * 'remainder' is the nonnegative number of 100-ns intervals
 * corresponding to the time fraction smaller than 1 second that
 * couldn't be stored in the time_t value.
Alexandre Julliard's avatar
Alexandre Julliard committed
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
void DOSFS_UnixTimeToFileTime( time_t unix_time, FILETIME *filetime,
                               DWORD remainder )
Alexandre Julliard's avatar
Alexandre Julliard committed
{
Alexandre Julliard's avatar
Alexandre Julliard committed
    /* NOTES:

       CONSTANTS:
Alexandre Julliard's avatar
Alexandre Julliard committed
       The time difference between 1 January 1601, 00:00:00 and
       1 January 1970, 00:00:00 is 369 years, plus the leap years
       from 1604 to 1968, excluding 1700, 1800, 1900.
       This makes (1968 - 1600) / 4 - 3 = 89 leap days, and a total
       of 134774 days.

       Any day in that period had 24 * 60 * 60 = 86400 seconds.

       The time difference is 134774 * 86400 * 10000000, which can be written
       116444736000000000
       27111902 * 2^32 + 3577643008
       413 * 2^48 + 45534 * 2^32 + 54590 * 2^16 + 32768

       If you find that these constants are buggy, please change them in all
       instances in both conversion functions.

       VERSIONS:
       There are two versions, one of them uses long long variables and
       is presumably faster but not ISO C. The other one uses standard C
       data types and operations but relies on the assumption that negative
       numbers are stored as 2's complement (-1 is 0xffff....). If this
       assumption is violated, dates before 1970 will not convert correctly.
       This should however work on any reasonable architecture where WINE
       will run.

       DETAILS:
Alexandre Julliard's avatar
Alexandre Julliard committed
       Take care not to remove the casts. I have tested these functions
       (in both versions) for a lot of numbers. I would be interested in
       results on other compilers than GCC.

       The operations have been designed to account for the possibility
       of 64-bit time_t in future UNICES. Even the versions without
       internal long long numbers will work if time_t only is 64 bit.
       A 32-bit shift, which was necessary for that operation, turned out
       not to work correctly in GCC, besides giving the warning. So I
       used a double 16-bit shift instead. Numbers are in the ISO version
       represented by three limbs, the most significant with 32 bit, the
       other two with 16 bit each.

       As the modulo-operator % is not well-defined for negative numbers,
       negative divisors have been avoided in DOSFS_FileTimeToUnixTime.

       There might be quicker ways to do this in C. Certainly so in
       assembler.

       Claus Fischer, fischer@iue.tuwien.ac.at
       */

#if SIZEOF_LONG_LONG >= 8
Alexandre Julliard's avatar
Alexandre Julliard committed
#  define USE_LONG_LONG 1
#else
#  define USE_LONG_LONG 0
#endif

#if USE_LONG_LONG		/* gcc supports long long type */

    long long int t = unix_time;
    t *= 10000000;
    t += 116444736000000000LL;
    t += remainder;
    filetime->dwLowDateTime  = (UINT)t;
    filetime->dwHighDateTime = (UINT)(t >> 32);
Alexandre Julliard's avatar
Alexandre Julliard committed

#else  /* ISO version */

    UINT a0;			/* 16 bit, low    bits */
    UINT a1;			/* 16 bit, medium bits */
    UINT a2;			/* 32 bit, high   bits */
Alexandre Julliard's avatar
Alexandre Julliard committed

    /* Copy the unix time to a2/a1/a0 */
    a0 =  unix_time & 0xffff;
    a1 = (unix_time >> 16) & 0xffff;
    /* This is obsolete if unix_time is only 32 bits, but it does not hurt.
       Do not replace this by >> 32, it gives a compiler warning and it does
       not work. */
    a2 = (unix_time >= 0 ? (unix_time >> 16) >> 16 :
	  ~((~unix_time >> 16) >> 16));

    /* Multiply a by 10000000 (a = a2/a1/a0)
       Split the factor into 10000 * 1000 which are both less than 0xffff. */
    a0 *= 10000;
    a1 = a1 * 10000 + (a0 >> 16);
    a2 = a2 * 10000 + (a1 >> 16);
    a0 &= 0xffff;
    a1 &= 0xffff;

    a0 *= 1000;
    a1 = a1 * 1000 + (a0 >> 16);
    a2 = a2 * 1000 + (a1 >> 16);
    a0 &= 0xffff;
    a1 &= 0xffff;

    /* Add the time difference and the remainder */
    a0 += 32768 + (remainder & 0xffff);
    a1 += 54590 + (remainder >> 16   ) + (a0 >> 16);
    a2 += 27111902                     + (a1 >> 16);
    a0 &= 0xffff;
    a1 &= 0xffff;

    /* Set filetime */
    filetime->dwLowDateTime  = (a1 << 16) + a0;
    filetime->dwHighDateTime = a2;
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
}
Alexandre Julliard's avatar
Alexandre Julliard committed
/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
 *           DOSFS_FileTimeToUnixTime
 *
 * Convert a FILETIME format to Unix time.
Alexandre Julliard's avatar
Alexandre Julliard committed
 * If not NULL, 'remainder' contains the fractional part of the filetime,
 * in the range of [0..9999999] (even if time_t is negative).
Alexandre Julliard's avatar
Alexandre Julliard committed
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
time_t DOSFS_FileTimeToUnixTime( const FILETIME *filetime, DWORD *remainder )
Alexandre Julliard's avatar
Alexandre Julliard committed
{
Alexandre Julliard's avatar
Alexandre Julliard committed
    /* Read the comment in the function DOSFS_UnixTimeToFileTime. */
#if USE_LONG_LONG

    long long int t = filetime->dwHighDateTime;
    t <<= 32;
    t += (UINT)filetime->dwLowDateTime;
Alexandre Julliard's avatar
Alexandre Julliard committed
    t -= 116444736000000000LL;
    if (t < 0)
    {
	if (remainder) *remainder = 9999999 - (-t - 1) % 10000000;
	return -1 - ((-t - 1) / 10000000);
    }
    else
    {
	if (remainder) *remainder = t % 10000000;
	return t / 10000000;
    }

#else  /* ISO version */

    UINT a0;			/* 16 bit, low    bits */
    UINT a1;			/* 16 bit, medium bits */
    UINT a2;			/* 32 bit, high   bits */
    UINT r;			/* remainder of division */
Alexandre Julliard's avatar
Alexandre Julliard committed
    unsigned int carry;		/* carry bit for subtraction */
    int negative;		/* whether a represents a negative value */

    /* Copy the time values to a2/a1/a0 */
    a2 =  (UINT)filetime->dwHighDateTime;
    a1 = ((UINT)filetime->dwLowDateTime ) >> 16;
    a0 = ((UINT)filetime->dwLowDateTime ) & 0xffff;
Alexandre Julliard's avatar
Alexandre Julliard committed

    /* Subtract the time difference */
    if (a0 >= 32768           ) a0 -=             32768        , carry = 0;
    else                        a0 += (1 << 16) - 32768        , carry = 1;

    if (a1 >= 54590    + carry) a1 -=             54590 + carry, carry = 0;
    else                        a1 += (1 << 16) - 54590 - carry, carry = 1;

    a2 -= 27111902 + carry;
Alexandre Julliard's avatar
Alexandre Julliard committed
    /* If a is negative, replace a by (-1-a) */
    negative = (a2 >= ((UINT)1) << 31);
Alexandre Julliard's avatar
Alexandre Julliard committed
    if (negative)
    {
	/* Set a to -a - 1 (a is a2/a1/a0) */
	a0 = 0xffff - a0;
	a1 = 0xffff - a1;
	a2 = ~a2;
    }

    /* Divide a by 10000000 (a = a2/a1/a0), put the rest into r.
       Split the divisor into 10000 * 1000 which are both less than 0xffff. */
    a1 += (a2 % 10000) << 16;
    a2 /=       10000;
    a0 += (a1 % 10000) << 16;
    a1 /=       10000;
    r   =  a0 % 10000;
    a0 /=       10000;

    a1 += (a2 % 1000) << 16;
    a2 /=       1000;
    a0 += (a1 % 1000) << 16;
    a1 /=       1000;
    r  += (a0 % 1000) * 10000;
    a0 /=       1000;

    /* If a was negative, replace a by (-1-a) and r by (9999999 - r) */
    if (negative)
    {
	/* Set a to -a - 1 (a is a2/a1/a0) */
	a0 = 0xffff - a0;
	a1 = 0xffff - a1;
	a2 = ~a2;

        r  = 9999999 - r;
    }

    if (remainder) *remainder = r;

    /* Do not replace this by << 32, it gives a compiler warning and it does
       not work. */
    return ((((time_t)a2) << 16) << 16) + (a1 << 16) + a0;
#endif
/***********************************************************************
 * RETURNS
 *	Result of multiplication and division
 *	-1: Overflow occurred or Divisor was 0
 */
INT WINAPI MulDiv(
	     INT nMultiplicand,
	     INT nMultiplier,
	     INT nDivisor)
{
#if SIZEOF_LONG_LONG >= 8
    long long ret;

    if (!nDivisor) return -1;

    /* We want to deal with a positive divisor to simplify the logic. */
    if (nDivisor < 0)
    {
      nMultiplicand = - nMultiplicand;
      nDivisor = -nDivisor;
    }

    /* If the result is positive, we "add" to round. else, we subtract to round. */
    if ( ( (nMultiplicand <  0) && (nMultiplier <  0) ) ||
	 ( (nMultiplicand >= 0) && (nMultiplier >= 0) ) )
      ret = (((long long)nMultiplicand * nMultiplier) + (nDivisor/2)) / nDivisor;
    else
      ret = (((long long)nMultiplicand * nMultiplier) - (nDivisor/2)) / nDivisor;

    if ((ret > 2147483647) || (ret < -2147483647)) return -1;
    return ret;
#else
    if (!nDivisor) return -1;

    /* We want to deal with a positive divisor to simplify the logic. */
    if (nDivisor < 0)
    {
      nMultiplicand = - nMultiplicand;
      nDivisor = -nDivisor;
    }

    /* If the result is positive, we "add" to round. else, we subtract to round. */
    if ( ( (nMultiplicand <  0) && (nMultiplier <  0) ) ||
	 ( (nMultiplicand >= 0) && (nMultiplier >= 0) ) )
      return ((nMultiplicand * nMultiplier) + (nDivisor/2)) / nDivisor;
    return ((nMultiplicand * nMultiplier) - (nDivisor/2)) / nDivisor;
Alexandre Julliard's avatar
Alexandre Julliard committed
/***********************************************************************
 *           DosDateTimeToFileTime   (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
 */
BOOL WINAPI DosDateTimeToFileTime( WORD fatdate, WORD fattime, LPFILETIME ft)
Alexandre Julliard's avatar
Alexandre Julliard committed
{
Alexandre Julliard's avatar
Alexandre Julliard committed
    struct tm newtm;
#ifndef HAVE_TIMEGM
    struct tm *gtm;
    time_t time1, time2;
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed

    newtm.tm_sec  = (fattime & 0x1f) * 2;
    newtm.tm_min  = (fattime >> 5) & 0x3f;
    newtm.tm_hour = (fattime >> 11);
    newtm.tm_mday = (fatdate & 0x1f);
    newtm.tm_mon  = ((fatdate >> 5) & 0x0f) - 1;
    newtm.tm_year = (fatdate >> 9) + 80;
    RtlSecondsSince1970ToTime( timegm(&newtm), (LARGE_INTEGER *)ft );
#else
    time1 = mktime(&newtm);
    gtm = gmtime(&time1);
    time2 = mktime(gtm);
    RtlSecondsSince1970ToTime( 2*time1-time2, (LARGE_INTEGER *)ft );
Alexandre Julliard's avatar
Alexandre Julliard committed
    return TRUE;
}


/***********************************************************************
 *           FileTimeToDosDateTime   (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
 */
BOOL WINAPI FileTimeToDosDateTime( const FILETIME *ft, LPWORD fatdate,
Alexandre Julliard's avatar
Alexandre Julliard committed
                                     LPWORD fattime )
Alexandre Julliard's avatar
Alexandre Julliard committed
{
Alexandre Julliard's avatar
Alexandre Julliard committed
    time_t unixtime = DOSFS_FileTimeToUnixTime( ft, NULL );
    struct tm *tm = gmtime( &unixtime );
Alexandre Julliard's avatar
Alexandre Julliard committed
    if (fattime)
        *fattime = (tm->tm_hour << 11) + (tm->tm_min << 5) + (tm->tm_sec / 2);
    if (fatdate)
        *fatdate = ((tm->tm_year - 80) << 9) + ((tm->tm_mon + 1) << 5)
                   + tm->tm_mday;
Alexandre Julliard's avatar
Alexandre Julliard committed
/***********************************************************************
 *           QueryDosDeviceA   (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
 *
 * returns array of strings terminated by \0, terminated by \0
 */
DWORD WINAPI QueryDosDeviceA(LPCSTR devname,LPSTR target,DWORD bufsize)
Alexandre Julliard's avatar
Alexandre Julliard committed
{
    LPSTR s;
    char  buffer[200];

    TRACE("(%s,...)\n", devname ? devname : "<null>");
Alexandre Julliard's avatar
Alexandre Julliard committed
    if (!devname) {
	/* return known MSDOS devices */
        static const char devices[24] = "CON\0COM1\0COM2\0LPT1\0NUL\0\0";
        memcpy( target, devices, min(bufsize,sizeof(devices)) );
        return min(bufsize,sizeof(devices));
Alexandre Julliard's avatar
Alexandre Julliard committed
    }
    /* In theory all that are possible and have been defined.
     * Now just those below, since mirc uses it to check for special files.
     *
     * (It is more complex, and supports netmounted stuff, and \\.\ stuff,
     *  but currently we just ignore that.)
     */
#define CHECK(x) (strstr(devname,#x)==devname)
    if (CHECK(con) || CHECK(com) || CHECK(lpt) || CHECK(nul)) {
	strcpy(buffer,"\\DEV\\");
	strcat(buffer,devname);
	if ((s=strchr(buffer,':'))) *s='\0';
	lstrcpynA(target,buffer,bufsize);
	return strlen(buffer)+1;
    } else {
	if (strchr(devname,':') || devname[0]=='\\') {
	    /* This might be a DOS device we do not handle yet ... */
	    FIXME("(%s) not detected as DOS device!\n",devname);
	}
	SetLastError(ERROR_DEV_NOT_EXIST);
	return 0;
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
}


/***********************************************************************
 *           QueryDosDeviceW   (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
 *
 * returns array of strings terminated by \0, terminated by \0
 */
DWORD WINAPI QueryDosDeviceW(LPCWSTR devname,LPWSTR target,DWORD bufsize)
Alexandre Julliard's avatar
Alexandre Julliard committed
{
    LPSTR devnameA = devname?HEAP_strdupWtoA(GetProcessHeap(),0,devname):NULL;
    LPSTR targetA = (LPSTR)HeapAlloc(GetProcessHeap(),0,bufsize);
    DWORD ret = QueryDosDeviceA(devnameA,targetA,bufsize);
    ret = MultiByteToWideChar( CP_ACP, 0, targetA, ret, target, bufsize );
Alexandre Julliard's avatar
Alexandre Julliard committed
    if (devnameA) HeapFree(GetProcessHeap(),0,devnameA);
    if (targetA) HeapFree(GetProcessHeap(),0,targetA);
    return ret;
}

Patrik Stridvall's avatar
Patrik Stridvall committed
/***********************************************************************
 *           DefineDosDeviceA       (KERNEL32.@)
BOOL WINAPI DefineDosDeviceA(DWORD flags,LPCSTR devname,LPCSTR targetpath) {
	FIXME("(0x%08lx,%s,%s),stub!\n",flags,devname,targetpath);
	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
	return FALSE;
}

/*
   --- 16 bit functions ---
*/

/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
 *           FindFirstFile   (KERNEL.413)
 */
HANDLE16 WINAPI FindFirstFile16( LPCSTR path, WIN32_FIND_DATAA *data )
{
    DOS_FULL_NAME full_name;
    HGLOBAL16 handle;
    FIND_FIRST_INFO *info;
    WCHAR pathW[MAX_PATH];
    char *p;
    INT long_mask_len;
    UINT codepage;

    data->dwReserved0 = data->dwReserved1 = 0x0;
    if (!path) return INVALID_HANDLE_VALUE16;
    MultiByteToWideChar(CP_ACP, 0, path, -1, pathW, MAX_PATH);
    if (!DOSFS_GetFullName( pathW, FALSE, &full_name ))
        return INVALID_HANDLE_VALUE16;
    if (!(handle = GlobalAlloc16( GMEM_MOVEABLE, sizeof(FIND_FIRST_INFO) )))
        return INVALID_HANDLE_VALUE16;
    info = (FIND_FIRST_INFO *)GlobalLock16( handle );
    info->path = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.long_name)+1 );
    strcpy( info->path, full_name.long_name );

    codepage = DRIVE_GetCodepage(full_name.drive);
    p = strrchr( info->path, '/' );
    *p++ = '\0';
    long_mask_len = MultiByteToWideChar(codepage, 0, p, -1, NULL, 0);
    info->long_mask = HeapAlloc( GetProcessHeap(), 0, long_mask_len * sizeof(WCHAR) );
    MultiByteToWideChar(codepage, 0, p, -1, info->long_mask, long_mask_len);

    info->short_mask = NULL;
    info->attr = 0xff;
    info->drive = full_name.drive;
    info->u.dos_dir = DOSFS_OpenDir( codepage, info->path );

    GlobalUnlock16( handle );
    if (!FindNextFile16( handle, data ))
    {
        FindClose16( handle );
        SetLastError( ERROR_NO_MORE_FILES );
        return INVALID_HANDLE_VALUE16;
    }
    return handle;
}

/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
 *           FindNextFile   (KERNEL.414)
 */
BOOL16 WINAPI FindNextFile16( HANDLE16 handle, WIN32_FIND_DATAA *data )
{
    FIND_FIRST_INFO *info;
    WIN32_FIND_DATAW dataW;
    BOOL ret = FALSE;
    DWORD gle = ERROR_NO_MORE_FILES;

    if ((handle == INVALID_HANDLE_VALUE16) ||
       !(info = (FIND_FIRST_INFO *)GlobalLock16( handle )))
    {
        SetLastError( ERROR_INVALID_HANDLE );
    if (!info->path || !info->u.dos_dir)
    if (!DOSFS_FindNextEx( info, &dataW ))
        DOSFS_CloseDir( info->u.dos_dir ); info->u.dos_dir = NULL;
        HeapFree( GetProcessHeap(), 0, info->path );
        info->path = NULL;
        HeapFree( GetProcessHeap(), 0, info->long_mask );
        info->long_mask = NULL;
        goto done;

    ret = TRUE;

    data->dwFileAttributes = dataW.dwFileAttributes;
    data->ftCreationTime   = dataW.ftCreationTime;
    data->ftLastAccessTime = dataW.ftLastAccessTime;
    data->ftLastWriteTime  = dataW.ftLastWriteTime;
    data->nFileSizeHigh    = dataW.nFileSizeHigh;
    data->nFileSizeLow     = dataW.nFileSizeLow;
    WideCharToMultiByte( CP_ACP, 0, dataW.cFileName, -1,
                         data->cFileName, sizeof(data->cFileName), NULL, NULL );
    WideCharToMultiByte( CP_ACP, 0, dataW.cAlternateFileName, -1,
                         data->cAlternateFileName,
                         sizeof(data->cAlternateFileName), NULL, NULL );
done:
    if( !ret ) SetLastError( gle );
    GlobalUnlock16( handle );

    return ret;
}

/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
 *           FindClose   (KERNEL.415)
 */
BOOL16 WINAPI FindClose16( HANDLE16 handle )
{
    FIND_FIRST_INFO *info;

    if ((handle == INVALID_HANDLE_VALUE16) ||
        !(info = (FIND_FIRST_INFO *)GlobalLock16( handle )))
    {
        SetLastError( ERROR_INVALID_HANDLE );
        return FALSE;
    }
    if (info->u.dos_dir) DOSFS_CloseDir( info->u.dos_dir );
    if (info->path) HeapFree( GetProcessHeap(), 0, info->path );
    if (info->long_mask) HeapFree( GetProcessHeap(), 0, info->long_mask );
    GlobalUnlock16( handle );
    GlobalFree16( handle );
    return TRUE;
}