Removed the DOSFS_ specific time related conversion routine, and make
use of the ntdll equivalents.
This commit is contained in:
parent
61f84c18d5
commit
f3d2a8d42d
233
files/dos_fs.c
233
files/dos_fs.c
@ -40,6 +40,8 @@
|
|||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define NONAMELESSUNION
|
||||||
|
#define NONAMELESSSTRUCT
|
||||||
#include "windef.h"
|
#include "windef.h"
|
||||||
#include "winerror.h"
|
#include "winerror.h"
|
||||||
#include "wingdi.h"
|
#include "wingdi.h"
|
||||||
@ -2238,225 +2240,6 @@ BOOL WINAPI FindClose( HANDLE handle )
|
|||||||
return FALSE;
|
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 )
|
|
||||||
{
|
|
||||||
/* NOTES:
|
|
||||||
|
|
||||||
CONSTANTS:
|
|
||||||
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:
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
#else /* ISO version */
|
|
||||||
|
|
||||||
UINT a0; /* 16 bit, low bits */
|
|
||||||
UINT a1; /* 16 bit, medium bits */
|
|
||||||
UINT a2; /* 32 bit, high bits */
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
|
|
||||||
/* If a is negative, replace a by (-1-a) */
|
|
||||||
negative = (a2 >= ((UINT)1) << 31);
|
|
||||||
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.@)
|
* MulDiv (KERNEL32.@)
|
||||||
* RETURNS
|
* RETURNS
|
||||||
@ -2545,8 +2328,16 @@ BOOL WINAPI DosDateTimeToFileTime( WORD fatdate, WORD fattime, LPFILETIME ft)
|
|||||||
BOOL WINAPI FileTimeToDosDateTime( const FILETIME *ft, LPWORD fatdate,
|
BOOL WINAPI FileTimeToDosDateTime( const FILETIME *ft, LPWORD fatdate,
|
||||||
LPWORD fattime )
|
LPWORD fattime )
|
||||||
{
|
{
|
||||||
time_t unixtime = DOSFS_FileTimeToUnixTime( ft, NULL );
|
LARGE_INTEGER li;
|
||||||
struct tm *tm = gmtime( &unixtime );
|
ULONG t;
|
||||||
|
time_t unixtime;
|
||||||
|
struct tm* tm;
|
||||||
|
|
||||||
|
li.s.LowPart = ft->dwLowDateTime;
|
||||||
|
li.s.HighPart = ft->dwHighDateTime;
|
||||||
|
RtlTimeToSecondsSince1970( &li, &t );
|
||||||
|
unixtime = t;
|
||||||
|
tm = gmtime( &unixtime );
|
||||||
if (fattime)
|
if (fattime)
|
||||||
*fattime = (tm->tm_hour << 11) + (tm->tm_min << 5) + (tm->tm_sec / 2);
|
*fattime = (tm->tm_hour << 11) + (tm->tm_min << 5) + (tm->tm_sec / 2);
|
||||||
if (fatdate)
|
if (fatdate)
|
||||||
|
@ -94,9 +94,6 @@ extern DWORD DIR_SearchPath( LPCWSTR path, LPCWSTR name, LPCWSTR ext,
|
|||||||
DOS_FULL_NAME *full_name, BOOL win32 );
|
DOS_FULL_NAME *full_name, BOOL win32 );
|
||||||
|
|
||||||
/* files/dos_fs.c */
|
/* files/dos_fs.c */
|
||||||
extern void DOSFS_UnixTimeToFileTime( time_t unixtime, LPFILETIME ft,
|
|
||||||
DWORD remainder );
|
|
||||||
extern time_t DOSFS_FileTimeToUnixTime( const FILETIME *ft, DWORD *remainder );
|
|
||||||
extern BOOL DOSFS_ToDosFCBFormat( LPCWSTR name, LPWSTR buffer );
|
extern BOOL DOSFS_ToDosFCBFormat( LPCWSTR name, LPWSTR buffer );
|
||||||
extern const DOS_DEVICE *DOSFS_GetDevice( LPCWSTR name );
|
extern const DOS_DEVICE *DOSFS_GetDevice( LPCWSTR name );
|
||||||
extern const DOS_DEVICE *DOSFS_GetDeviceByHandle( HANDLE hFile );
|
extern const DOS_DEVICE *DOSFS_GetDeviceByHandle( HANDLE hFile );
|
||||||
|
Loading…
x
Reference in New Issue
Block a user