Fixed some issues found by winapi_check.
[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  * FIXME: correct ? Is the timezone param of settimeofday() needed ?
37  * I don't have any docu about SetLocal/SystemTime(), argl...
38  */
39 BOOL WINAPI SetLocalTime(const SYSTEMTIME *systime)
40 {
41     struct timeval tv;
42     struct tm t;
43     time_t sec;
44     time_t oldsec=time(NULL);
45     int err;
46
47     /* get the number of seconds */
48     t.tm_sec = systime->wSecond;
49     t.tm_min = systime->wMinute;
50     t.tm_hour = systime->wHour;
51     t.tm_mday = systime->wDay;
52     t.tm_mon = systime->wMonth - 1;
53     t.tm_year = systime->wYear - 1900;
54     t.tm_isdst = -1;
55     sec = mktime (&t);
56
57     /* set the new time */
58     tv.tv_sec = sec;
59     tv.tv_usec = systime->wMilliseconds * 1000;
60
61     /* error and sanity check*/
62     if( sec == (time_t)-1 || abs((int)(sec-oldsec)) > SETTIME_MAX_ADJUST ){
63         err = 1;
64         SetLastError(ERROR_INVALID_PARAMETER);
65     } else {
66         err=settimeofday(&tv, NULL); /* 0 is OK, -1 is error */
67         if(err == 0)
68             return TRUE;
69         SetLastError(ERROR_PRIVILEGE_NOT_HELD);
70     }
71     ERR("Cannot set time to %d/%d/%d %d:%d:%d Time adjustment %ld %s\n",
72             systime->wYear, systime->wMonth, systime->wDay, systime->wHour,
73             systime->wMinute, systime->wSecond,
74             sec-oldsec, err == -1 ? "No Permission" : 
75                 sec==(time_t)-1 ? "" : "is too large." );
76     return FALSE;
77 }
78
79
80 /***********************************************************************
81  *           GetSystemTimeAdjustment     (KERNEL32.407)
82  *
83  */
84 DWORD WINAPI GetSystemTimeAdjustment( LPDWORD lpTimeAdjustment,
85                                       LPDWORD lpTimeIncrement,
86                                       LPBOOL lpTimeAdjustmentDisabled )
87 {
88     *lpTimeAdjustment = 0;
89     *lpTimeIncrement = 0;
90     *lpTimeAdjustmentDisabled = TRUE;
91     return TRUE;
92 }
93
94
95 /***********************************************************************
96  *              SetSystemTime            (KERNEL32.507)
97  */
98 BOOL WINAPI SetSystemTime(const SYSTEMTIME *systime)
99 {
100     struct timeval tv;
101     struct timezone tz;
102     struct tm t;
103     time_t sec, oldsec;
104     int dst, bias;
105     int err;
106
107     /* call gettimeofday to get the current timezone */
108     gettimeofday(&tv, &tz);
109     oldsec=tv.tv_sec;
110     /* get delta local time from utc */
111     bias=TIME_GetBias(oldsec,&dst);
112
113     /* get the number of seconds */
114     t.tm_sec = systime->wSecond;
115     t.tm_min = systime->wMinute;
116     t.tm_hour = systime->wHour;
117     t.tm_mday = systime->wDay;
118     t.tm_mon = systime->wMonth - 1;
119     t.tm_year = systime->wYear - 1900;
120     t.tm_isdst = dst;
121     sec = mktime (&t);
122     /* correct for timezone and daylight */
123     sec += bias;
124
125     /* set the new time */
126     tv.tv_sec = sec;
127     tv.tv_usec = systime->wMilliseconds * 1000;
128
129     /* error and sanity check*/
130     if( sec == (time_t)-1 || abs((int)(sec-oldsec)) > SETTIME_MAX_ADJUST ){
131         err = 1;
132         SetLastError(ERROR_INVALID_PARAMETER);
133     } else {
134         err=settimeofday(&tv, NULL); /* 0 is OK, -1 is error */
135         if(err == 0)
136             return TRUE;
137         SetLastError(ERROR_PRIVILEGE_NOT_HELD);
138     }
139     ERR("Cannot set time to %d/%d/%d %d:%d:%d Time adjustment %ld %s\n",
140             systime->wYear, systime->wMonth, systime->wDay, systime->wHour,
141             systime->wMinute, systime->wSecond,
142             sec-oldsec, err == -1 ? "No Permission" :
143                 sec==(time_t)-1 ? "" : "is too large." );
144     return FALSE;
145 }
146
147
148 /***********************************************************************
149  *              GetTimeZoneInformation  (KERNEL32.302)
150  */
151 DWORD WINAPI GetTimeZoneInformation(LPTIME_ZONE_INFORMATION tzinfo)
152 {
153     time_t gmt;
154     int bias, daylight;
155
156     memset(tzinfo, 0, sizeof(TIME_ZONE_INFORMATION));
157
158     gmt = time(NULL);
159     bias=TIME_GetBias(gmt,&daylight);
160
161     tzinfo->Bias = -bias / 60;
162     tzinfo->StandardBias = 0;
163     tzinfo->DaylightBias = -60;
164
165     return TIME_ZONE_ID_STANDARD;
166 }
167
168
169 /***********************************************************************
170  *              SetTimeZoneInformation  (KERNEL32.515)
171  */
172 BOOL WINAPI SetTimeZoneInformation(const LPTIME_ZONE_INFORMATION tzinfo)
173 {
174     struct timezone tz;
175
176     tz.tz_minuteswest = tzinfo->Bias;
177 #ifdef DST_NONE
178     tz.tz_dsttime = DST_NONE;
179 #else
180     tz.tz_dsttime = 0;
181 #endif
182     return !settimeofday(NULL, &tz);
183 }
184
185
186 /***********************************************************************
187  *              SystemTimeToTzSpecificLocalTime  (KERNEL32.683)
188  */
189 BOOL WINAPI SystemTimeToTzSpecificLocalTime(
190   LPTIME_ZONE_INFORMATION lpTimeZoneInformation,
191   LPSYSTEMTIME lpUniversalTime,
192   LPSYSTEMTIME lpLocalTime)
193 {
194   FIXME(":stub\n");
195   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
196        return FALSE;
197 }
198
199
200 /***********************************************************************
201  *              GetSystemTimeAsFileTime  (KERNEL32)
202  */
203 VOID WINAPI GetSystemTimeAsFileTime( LPFILETIME time )
204 {
205     NtQuerySystemTime( (LARGE_INTEGER *)time );
206 }
207
208
209 /*********************************************************************
210  *      TIME_ClockTimeToFileTime
211  *      (olorin@fandra.org, 20-Sep-1998)
212  *      Converts clock_t into FILETIME.
213  *      Used by GetProcessTime.
214  *      Differences to UnixTimeToFileTime:
215  *          1) Divided by CLK_TCK
216  *          2) Time is relative. There is no 'starting date', so there is 
217  *             no need in offset correction, like in UnixTimeToFileTime
218  */
219 static void TIME_ClockTimeToFileTime(clock_t unix_time, LPFILETIME filetime)
220 {
221     LONGLONG secs = RtlEnlargedUnsignedMultiply( unix_time, 10000000 );
222     ((LARGE_INTEGER *)filetime)->QuadPart = RtlExtendedLargeIntegerDivide( secs, CLK_TCK, NULL );
223 }
224
225 /*********************************************************************
226  *      GetProcessTimes                         [KERNEL32.262]
227  *
228  * FIXME: lpCreationTime, lpExitTime are NOT INITIALIZED.
229  * olorin@fandra.org: Would be nice to substract the cpu time,
230  *                    used by Wine at startup.
231  *                    Also, there is a need to separate times
232  *                    used by different applications.
233  */
234 BOOL WINAPI GetProcessTimes( HANDLE hprocess,LPFILETIME lpCreationTime,LPFILETIME lpExitTime,
235                              LPFILETIME lpKernelTime, LPFILETIME lpUserTime )
236 {
237     struct tms tms;
238
239     times(&tms);
240     TIME_ClockTimeToFileTime(tms.tms_utime,lpUserTime);
241     TIME_ClockTimeToFileTime(tms.tms_stime,lpKernelTime);
242     return TRUE;
243 }