common: Check option arguments for a valid range.
[gnupg.git] / common / mischelp.c
1 /* mischelp.c - Miscellaneous helper functions
2  * Copyright (C) 1998, 2000, 2001, 2006, 2007 Free Software Foundation, Inc.
3  *
4  * This file is part of JNLIB, which is a subsystem of GnuPG.
5  *
6  * JNLIB is free software; you can redistribute it and/or modify it
7  * under the terms of either
8  *
9  *   - the GNU Lesser General Public License as published by the Free
10  *     Software Foundation; either version 3 of the License, or (at
11  *     your option) any later version.
12  *
13  * or
14  *
15  *   - the GNU General Public License as published by the Free
16  *     Software Foundation; either version 2 of the License, or (at
17  *     your option) any later version.
18  *
19  * or both in parallel, as here.
20  *
21  * JNLIB is distributed in the hope that it will be useful, but
22  * WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * General Public License for more details.
25  *
26  * You should have received a copies of the GNU General Public License
27  * and the GNU Lesser General Public License along with this program;
28  * if not, see <http://www.gnu.org/licenses/>.
29  */
30
31 #include <config.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <time.h>
35 #ifdef HAVE_W32_SYSTEM
36 # define WIN32_LEAN_AND_MEAN
37 # include <windows.h>
38 #else /*!HAVE_W32_SYSTEM*/
39 # include <sys/types.h>
40 # include <sys/stat.h>
41 # include <unistd.h>
42 #endif /*!HAVE_W32_SYSTEM*/
43 #include <errno.h>
44
45 #include "libjnlib-config.h"
46 #include "stringhelp.h"
47 #include "utf8conv.h"
48 #include "mischelp.h"
49
50
51 /* Because we can't use our jnlib_free macro in inline functions we
52    provide this wrapper.  */
53 void
54 _jnlib_free (void *p)
55 {
56   if (p)
57     jnlib_free (p);
58 }
59
60
61 /* Check whether the files NAME1 and NAME2 are identical.  This is for
62    example achieved by comparing the inode numbers of the files.  */
63 int
64 same_file_p (const char *name1, const char *name2)
65 {
66   int yes;
67
68   /* First try a shortcut.  */
69   if (!compare_filenames (name1, name2))
70     yes = 1;
71   else
72     {
73 #ifdef HAVE_W32_SYSTEM
74       HANDLE file1, file2;
75       BY_HANDLE_FILE_INFORMATION info1, info2;
76
77 #ifdef HAVE_W32CE_SYSTEM
78       {
79         wchar_t *wname = utf8_to_wchar (name1);
80         if (wname)
81           file1 = CreateFile (wname, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
82         else
83           file1 = INVALID_HANDLE_VALUE;
84         jnlib_free (wname);
85       }
86 #else
87       file1 = CreateFile (name1, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
88 #endif
89       if (file1 == INVALID_HANDLE_VALUE)
90         yes = 0; /* If we can't open the file, it is not the same.  */
91       else
92         {
93 #ifdef HAVE_W32CE_SYSTEM
94           {
95             wchar_t *wname = utf8_to_wchar (name2);
96             if (wname)
97               file2 = CreateFile (wname, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
98             else
99               file2 = INVALID_HANDLE_VALUE;
100             jnlib_free (wname);
101           }
102 #else
103           file2 = CreateFile (name2, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
104 #endif
105           if (file2 == INVALID_HANDLE_VALUE)
106             yes = 0; /* If we can't open the file, it is not the same.  */
107           else
108             {
109               yes = (GetFileInformationByHandle (file1, &info1)
110                      && GetFileInformationByHandle (file2, &info2)
111                      && info1.dwVolumeSerialNumber==info2.dwVolumeSerialNumber
112                      && info1.nFileIndexHigh == info2.nFileIndexHigh
113                      && info1.nFileIndexLow == info2.nFileIndexLow);
114               CloseHandle (file2);
115             }
116           CloseHandle (file1);
117         }
118 #else /*!HAVE_W32_SYSTEM*/
119       struct stat info1, info2;
120
121       yes = (!stat (name1, &info1) && !stat (name2, &info2)
122              && info1.st_dev == info2.st_dev && info1.st_ino == info2.st_ino);
123 #endif /*!HAVE_W32_SYSTEM*/
124     }
125   return yes;
126 }
127
128
129 /*
130   timegm() is a GNU function that might not be available everywhere.
131   It's basically the inverse of gmtime() - you give it a struct tm,
132   and get back a time_t.  It differs from mktime() in that it handles
133   the case where the struct tm is UTC and the local environment isn't.
134
135   Note, that this replacement implementation might not be thread-safe!
136
137   Some BSDs don't handle the putenv("foo") case properly, so we use
138   unsetenv if the platform has it to remove environment variables.
139 */
140 #ifndef HAVE_TIMEGM
141 time_t
142 timegm (struct tm *tm)
143 {
144 #ifdef HAVE_W32_SYSTEM
145   /* This one is thread safe.  */
146   SYSTEMTIME st;
147   FILETIME ft;
148   unsigned long long cnsecs;
149
150   st.wYear   = tm->tm_year + 1900;
151   st.wMonth  = tm->tm_mon  + 1;
152   st.wDay    = tm->tm_mday;
153   st.wHour   = tm->tm_hour;
154   st.wMinute = tm->tm_min;
155   st.wSecond = tm->tm_sec;
156   st.wMilliseconds = 0; /* Not available.  */
157   st.wDayOfWeek = 0;    /* Ignored.  */
158
159   /* System time is UTC thus the conversion is pretty easy.  */
160   if (!SystemTimeToFileTime (&st, &ft))
161     {
162       jnlib_set_errno (EINVAL);
163       return (time_t)(-1);
164     }
165
166   cnsecs = (((unsigned long long)ft.dwHighDateTime << 32)
167             | ft.dwLowDateTime);
168   cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01.  */
169   return (time_t)(cnsecs / 10000000ULL);
170
171 #else /* (Non thread safe implementation!) */
172
173   time_t answer;
174   char *zone;
175
176   zone=getenv("TZ");
177   putenv("TZ=UTC");
178   tzset();
179   answer=mktime(tm);
180   if(zone)
181     {
182       static char *old_zone;
183
184       if (!old_zone)
185         {
186           old_zone = malloc(3+strlen(zone)+1);
187           if (old_zone)
188             {
189               strcpy(old_zone,"TZ=");
190               strcat(old_zone,zone);
191             }
192         }
193       if (old_zone)
194         putenv (old_zone);
195     }
196   else
197     gnupg_unsetenv("TZ");
198
199   tzset();
200   return answer;
201 #endif
202 }
203 #endif /*!HAVE_TIMEGM*/