- implemented passive FTP transfers (PASV, needed for firewalls)
[wine] / dlls / kernel / time.c
1 /*
2  * Win32 kernel functions
3  *
4  * Copyright 1995 Martin von Loewis and Cameron Heide
5  */
6
7 #include <string.h>
8 #include <unistd.h>
9 #include <stdlib.h>
10 #include <sys/time.h>
11 #include <sys/times.h>
12 #include "file.h"
13 #include "ntddk.h"
14 #include "winerror.h"
15 #include "debugtools.h"
16
17 DEFAULT_DEBUG_CHANNEL(win32);
18
19 /* maximum time adjustment in seconds for SetLocalTime and SetSystemTime */
20 #define SETTIME_MAX_ADJUST 120
21
22 /* TIME_GetBias: helper function calculates delta local time from UTC */
23 static int TIME_GetBias( time_t utc, int *pdaylight)
24 {
25     struct tm *ptm = localtime(&utc);
26     *pdaylight = ptm->tm_isdst; /* daylight for local timezone */
27     ptm = gmtime(&utc);
28     ptm->tm_isdst = *pdaylight; /* use local daylight, not that of Greenwich */
29     return (int)(utc-mktime(ptm));
30 }
31
32
33 /***********************************************************************
34  *              SetLocalTime            (KERNEL32.655)
35  *
36  *  Sets the local time using current time zone and daylight
37  *  savings settings.
38  *
39  * RETURNS
40  *
41  *  True if the time was set, false if the time was invalid or the
42  *  necessary permissions were not held.
43  */
44 BOOL WINAPI SetLocalTime( const SYSTEMTIME *systime /* The desired local time. */ )
45 {
46     struct timeval tv;
47     struct tm t;
48     time_t sec;
49     time_t oldsec=time(NULL);
50     int err;
51
52     /* get the number of seconds */
53     t.tm_sec = systime->wSecond;
54     t.tm_min = systime->wMinute;
55     t.tm_hour = systime->wHour;
56     t.tm_mday = systime->wDay;
57     t.tm_mon = systime->wMonth - 1;
58     t.tm_year = systime->wYear - 1900;
59     t.tm_isdst = -1;
60     sec = mktime (&t);
61
62     /* set the new time */
63     tv.tv_sec = sec;
64     tv.tv_usec = systime->wMilliseconds * 1000;
65
66     /* error and sanity check*/
67     if( sec == (time_t)-1 || abs((int)(sec-oldsec)) > SETTIME_MAX_ADJUST ){
68         err = 1;
69         SetLastError(ERROR_INVALID_PARAMETER);
70     } else {
71         err=settimeofday(&tv, NULL); /* 0 is OK, -1 is error */
72         if(err == 0)
73             return TRUE;
74         SetLastError(ERROR_PRIVILEGE_NOT_HELD);
75     }
76     ERR("Cannot set time to %d/%d/%d %d:%d:%d Time adjustment %ld %s\n",
77             systime->wYear, systime->wMonth, systime->wDay, systime->wHour,
78             systime->wMinute, systime->wSecond,
79             sec-oldsec, err == -1 ? "No Permission" : 
80                 sec==(time_t)-1 ? "" : "is too large." );
81     return FALSE;
82 }
83
84
85 /***********************************************************************
86  *           GetSystemTimeAdjustment     (KERNEL32.407)
87  *
88  *  Indicates the period between clock interrupt and the amount the clock
89  *  is adjusted each interrupt so as to keep it insync with an external source.
90  *
91  * RETURNS
92  *
93  *  Always returns true.
94  *
95  * BUGS
96  *
97  *  Only the special case of disabled time adjustments is supported.
98  *  (also the signature is wrong it should have a return type of BOOL)
99  */
100 DWORD WINAPI GetSystemTimeAdjustment(
101          LPDWORD lpTimeAdjustment, /* The clock adjustment per interupt in 100's of nanoseconds. */
102          LPDWORD lpTimeIncrement, /* The time between clock interupts in 100's of nanoseconds. */
103          LPBOOL lpTimeAdjustmentDisabled /* The clock synchonisation has been disabled. */ )
104 {
105     *lpTimeAdjustment = 0;
106     *lpTimeIncrement = 0;
107     *lpTimeAdjustmentDisabled = TRUE;
108     return TRUE;
109 }
110
111
112 /***********************************************************************
113  *              SetSystemTime            (KERNEL32.507)
114  *
115  *  Sets the system time (utc).
116  *
117  * RETURNS
118  *
119  *  True if the time was set, false if the time was invalid or the
120  *  necessary permissions were not held.
121  */
122 BOOL WINAPI SetSystemTime(
123     const SYSTEMTIME *systime /* The desired system time. */)
124 {
125     struct timeval tv;
126     struct timezone tz;
127     struct tm t;
128     time_t sec, oldsec;
129     int dst, bias;
130     int err;
131
132     /* call gettimeofday to get the current timezone */
133     gettimeofday(&tv, &tz);
134     oldsec=tv.tv_sec;
135     /* get delta local time from utc */
136     bias=TIME_GetBias(oldsec,&dst);
137
138     /* get the number of seconds */
139     t.tm_sec = systime->wSecond;
140     t.tm_min = systime->wMinute;
141     t.tm_hour = systime->wHour;
142     t.tm_mday = systime->wDay;
143     t.tm_mon = systime->wMonth - 1;
144     t.tm_year = systime->wYear - 1900;
145     t.tm_isdst = dst;
146     sec = mktime (&t);
147     /* correct for timezone and daylight */
148     sec += bias;
149
150     /* set the new time */
151     tv.tv_sec = sec;
152     tv.tv_usec = systime->wMilliseconds * 1000;
153
154     /* error and sanity check*/
155     if( sec == (time_t)-1 || abs((int)(sec-oldsec)) > SETTIME_MAX_ADJUST ){
156         err = 1;
157         SetLastError(ERROR_INVALID_PARAMETER);
158     } else {
159         err=settimeofday(&tv, NULL); /* 0 is OK, -1 is error */
160         if(err == 0)
161             return TRUE;
162         SetLastError(ERROR_PRIVILEGE_NOT_HELD);
163     }
164     ERR("Cannot set time to %d/%d/%d %d:%d:%d Time adjustment %ld %s\n",
165             systime->wYear, systime->wMonth, systime->wDay, systime->wHour,
166             systime->wMinute, systime->wSecond,
167             sec-oldsec, err == -1 ? "No Permission" :
168                 sec==(time_t)-1 ? "" : "is too large." );
169     return FALSE;
170 }
171
172
173 /***********************************************************************
174  *              GetTimeZoneInformation  (KERNEL32.302)
175  *
176  *  Fills in the a time zone information structure with values based on
177  *  the current local time.
178  *
179  * RETURNS
180  *
181  *  The daylight savings time standard or TIME_ZONE_ID_INVALID if the call failed.
182  */
183 DWORD WINAPI GetTimeZoneInformation(
184         LPTIME_ZONE_INFORMATION tzinfo /* The time zone structure to be filled in. */)
185 {
186     time_t gmt;
187     int bias, daylight;
188
189     memset(tzinfo, 0, sizeof(TIME_ZONE_INFORMATION));
190
191     gmt = time(NULL);
192     bias=TIME_GetBias(gmt,&daylight);
193
194     tzinfo->Bias = -bias / 60;
195     tzinfo->StandardBias = 0;
196     tzinfo->DaylightBias = -60;
197
198     return TIME_ZONE_ID_STANDARD;
199 }
200
201
202 /***********************************************************************
203  *              SetTimeZoneInformation  (KERNEL32.515)
204  *
205  *  Set the local time zone with values based on the time zone structure.
206  *
207  * RETURNS
208  *
209  *  True on successful setting of the time zone.
210  *
211  * BUGS
212  *
213  *  Use the obsolete unix timezone structure and tz_dsttime member.
214  */
215 BOOL WINAPI SetTimeZoneInformation(
216         const LPTIME_ZONE_INFORMATION tzinfo /* The new time zone. */)
217 {
218     struct timezone tz;
219
220     tz.tz_minuteswest = tzinfo->Bias;
221 #ifdef DST_NONE
222     tz.tz_dsttime = DST_NONE;
223 #else
224     tz.tz_dsttime = 0;
225 #endif
226     return !settimeofday(NULL, &tz);
227 }
228
229
230 /***********************************************************************
231  *              SystemTimeToTzSpecificLocalTime  (KERNEL32.683)
232  *
233  *  Converts the system time (utc) to the local time in the specified time zone.
234  *
235  * RETURNS
236  *
237  *  Returns true when the local time was calculated.
238  *
239  * BUGS
240  *
241  *  Does not handle daylight savings time adjustments correctly.
242  */
243 BOOL WINAPI SystemTimeToTzSpecificLocalTime(
244         LPTIME_ZONE_INFORMATION lpTimeZoneInformation, /* The desired time zone. */
245         LPSYSTEMTIME lpUniversalTime, /* The utc time to base local time on. */
246         LPSYSTEMTIME lpLocalTime /* The local time in the time zone. */)
247 {
248   FIXME(":stub\n");
249   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
250        return FALSE;
251 }
252
253
254 /***********************************************************************
255  *              GetSystemTimeAsFileTime  (KERNEL32)
256  *
257  *  Fills in a file time structure with the current time in UTC format.
258  */
259 VOID WINAPI GetSystemTimeAsFileTime(
260         LPFILETIME time /* The file time struct to be filled with the system time. */)
261 {
262     NtQuerySystemTime( (LARGE_INTEGER *)time );
263 }
264
265
266 /*********************************************************************
267  *      TIME_ClockTimeToFileTime    (olorin@fandra.org, 20-Sep-1998)
268  *
269  *  Used by GetProcessTimes to convert clock_t into FILETIME.
270  *
271  *      Differences to UnixTimeToFileTime:
272  *          1) Divided by CLK_TCK
273  *          2) Time is relative. There is no 'starting date', so there is 
274  *             no need in offset correction, like in UnixTimeToFileTime
275  */
276 static void TIME_ClockTimeToFileTime(clock_t unix_time, LPFILETIME filetime)
277 {
278     LONGLONG secs = RtlEnlargedUnsignedMultiply( unix_time, 10000000 );
279     ((LARGE_INTEGER *)filetime)->QuadPart = RtlExtendedLargeIntegerDivide( secs, CLK_TCK, NULL );
280 }
281
282 /*********************************************************************
283  *      GetProcessTimes                         [KERNEL32.262]
284  *
285  *  Returns the user and kernel execution times of a process,
286  *  along with the creation and exit times if known.
287  *
288  *  olorin@fandra.org:
289  *  Would be nice to subtract the cpu time, used by Wine at startup.
290  *  Also, there is a need to separate times used by different applications.
291  *
292  * RETURNS
293  *
294  *  Always returns true.
295  *
296  * BUGS
297  *
298  *  lpCreationTime, lpExitTime are NOT INITIALIZED.
299  */
300 BOOL WINAPI GetProcessTimes(
301         HANDLE hprocess, /* The process to be queried (obtained from PROCESS_QUERY_INFORMATION). */
302         LPFILETIME lpCreationTime, /* The creation time of the process. */
303         LPFILETIME lpExitTime, /* The exit time of the process if exited. */
304         LPFILETIME lpKernelTime, /* The time spent in kernal routines in 100's of nanoseconds. */
305         LPFILETIME lpUserTime /* The time spent in user routines in 100's of nanoseconds. */)
306 {
307     struct tms tms;
308
309     times(&tms);
310     TIME_ClockTimeToFileTime(tms.tms_utime,lpUserTime);
311     TIME_ClockTimeToFileTime(tms.tms_stime,lpKernelTime);
312     return TRUE;
313 }