Newer
Older
HANDLE WINAPI FindFirstFileA(
LPCSTR lpFileName,
WIN32_FIND_DATAA *lpFindData )
return FindFirstFileExA(lpFileName, FindExInfoStandard, lpFindData,
FindExSearchNameMatch, NULL, 0);
}
/*************************************************************************
* FindFirstFileExA (KERNEL32.@)
HANDLE WINAPI FindFirstFileExA(
LPCSTR lpFileName,
FINDEX_INFO_LEVELS fInfoLevelId,
LPVOID lpFindFileData,
FINDEX_SEARCH_OPS fSearchOp,
LPVOID lpSearchFilter,
DWORD dwAdditionalFlags)
HANDLE handle;
WIN32_FIND_DATAA *dataA;
WIN32_FIND_DATAW dataW;
UNICODE_STRING pathW;
SetLastError(ERROR_PATH_NOT_FOUND);
return INVALID_HANDLE_VALUE;
if (!RtlCreateUnicodeStringFromAsciiz(&pathW, lpFileName))
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return INVALID_HANDLE_VALUE;
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 );
/*************************************************************************
* FindFirstFileW (KERNEL32.@)
*/
HANDLE WINAPI FindFirstFileW( LPCWSTR lpFileName, WIN32_FIND_DATAW *lpFindData )
{
return FindFirstFileExW(lpFileName, FindExInfoStandard, lpFindData,
FindExSearchNameMatch, NULL, 0);
}
/*************************************************************************
* FindNextFileW (KERNEL32.@)
BOOL WINAPI FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *data )
BOOL ret = FALSE;
!(info = (FIND_FIRST_INFO *)GlobalLock( handle )))
SetLastError( ERROR_INVALID_HANDLE );
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)
else if (!DOSFS_FindNextEx( info, data ))
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;
done:
GlobalUnlock( handle );
}
/*************************************************************************
* FindNextFileA (KERNEL32.@)
BOOL WINAPI FindNextFileA( HANDLE handle, WIN32_FIND_DATAA *data )
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,
data->cAlternateFileName,
sizeof(data->cAlternateFileName), NULL, NULL );
return TRUE;
}
/*************************************************************************
* FindClose (KERNEL32.@)
BOOL WINAPI FindClose( HANDLE handle )
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)
{
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
__ENDTRY
if (!info) goto error;
GlobalUnlock( handle );
GlobalFree( handle );
error:
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
/***********************************************************************
* DOSFS_UnixTimeToFileTime
*
* Convert a Unix time to FILETIME format.
* The FILETIME structure is a 64-bit value representing the number of
* 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.
void DOSFS_UnixTimeToFileTime( time_t unix_time, FILETIME *filetime,
DWORD remainder )
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
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:
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
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
# 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);
UINT a0; /* 16 bit, low bits */
UINT a1; /* 16 bit, medium bits */
UINT a2; /* 32 bit, high bits */
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
/* 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
/***********************************************************************
* DOSFS_FileTimeToUnixTime
*
* Convert a FILETIME format to Unix time.
* If not NULL, 'remainder' contains the fractional part of the filetime,
* in the range of [0..9999999] (even if time_t is negative).
time_t DOSFS_FileTimeToUnixTime( const FILETIME *filetime, DWORD *remainder )
/* Read the comment in the function DOSFS_UnixTimeToFileTime. */
#if USE_LONG_LONG
long long int t = filetime->dwHighDateTime;
t <<= 32;
t += (UINT)filetime->dwLowDateTime;
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 */
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;
/* 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;
negative = (a2 >= ((UINT)1) << 31);
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
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
/***********************************************************************
* MulDiv (KERNEL32.@)
* RETURNS
* Result of multiplication and division
* -1: Overflow occurred or Divisor was 0
*/
INT WINAPI MulDiv(
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
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;
#endif
}
/***********************************************************************
* DosDateTimeToFileTime (KERNEL32.@)
BOOL WINAPI DosDateTimeToFileTime( WORD fatdate, WORD fattime, LPFILETIME ft)
#ifndef HAVE_TIMEGM
struct tm *gtm;
time_t time1, time2;
#endif
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;
#ifdef HAVE_TIMEGM
RtlSecondsSince1970ToTime( timegm(&newtm), (LARGE_INTEGER *)ft );
#else
time1 = mktime(&newtm);
gtm = gmtime(&time1);
time2 = mktime(gtm);
RtlSecondsSince1970ToTime( 2*time1-time2, (LARGE_INTEGER *)ft );
#endif
return TRUE;
}
/***********************************************************************
* FileTimeToDosDateTime (KERNEL32.@)
BOOL WINAPI FileTimeToDosDateTime( const FILETIME *ft, LPWORD fatdate,
time_t unixtime = DOSFS_FileTimeToUnixTime( ft, NULL );
struct tm *tm = gmtime( &unixtime );
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;
/***********************************************************************
* QueryDosDeviceA (KERNEL32.@)
*
* returns array of strings terminated by \0, terminated by \0
*/
DWORD WINAPI QueryDosDeviceA(LPCSTR devname,LPSTR target,DWORD bufsize)
TRACE("(%s,...)\n", devname ? devname : "<null>");
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));
/* 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;
}
}
/***********************************************************************
* QueryDosDeviceW (KERNEL32.@)
*
* returns array of strings terminated by \0, terminated by \0
*/
DWORD WINAPI QueryDosDeviceW(LPCWSTR devname,LPWSTR target,DWORD bufsize)
{
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 );
if (devnameA) HeapFree(GetProcessHeap(),0,devnameA);
if (targetA) HeapFree(GetProcessHeap(),0,targetA);
return ret;
}
/***********************************************************************
* 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 ---
*/
/*************************************************************************
*/
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->cur_pos = 0;
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;
}
/*************************************************************************
*/
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;
}
/*************************************************************************
*/
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;
}