common: Change license of mbox-util to LGPLv2.1+.
[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 GnuPG.
5  *
6  * GnuPG 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  * GnuPG 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 "util.h"
46 #include "common-defs.h"
47 #include "stringhelp.h"
48 #include "utf8conv.h"
49 #include "mischelp.h"
50
51
52 /* Check whether the files NAME1 and NAME2 are identical.  This is for
53    example achieved by comparing the inode numbers of the files.  */
54 int
55 same_file_p (const char *name1, const char *name2)
56 {
57   int yes;
58
59   /* First try a shortcut.  */
60   if (!compare_filenames (name1, name2))
61     yes = 1;
62   else
63     {
64 #ifdef HAVE_W32_SYSTEM
65       HANDLE file1, file2;
66       BY_HANDLE_FILE_INFORMATION info1, info2;
67
68 #ifdef HAVE_W32CE_SYSTEM
69       {
70         wchar_t *wname = utf8_to_wchar (name1);
71         if (wname)
72           file1 = CreateFile (wname, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
73         else
74           file1 = INVALID_HANDLE_VALUE;
75         xfree (wname);
76       }
77 #else
78       file1 = CreateFile (name1, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
79 #endif
80       if (file1 == INVALID_HANDLE_VALUE)
81         yes = 0; /* If we can't open the file, it is not the same.  */
82       else
83         {
84 #ifdef HAVE_W32CE_SYSTEM
85           {
86             wchar_t *wname = utf8_to_wchar (name2);
87             if (wname)
88               file2 = CreateFile (wname, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
89             else
90               file2 = INVALID_HANDLE_VALUE;
91             xfree (wname);
92           }
93 #else
94           file2 = CreateFile (name2, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
95 #endif
96           if (file2 == INVALID_HANDLE_VALUE)
97             yes = 0; /* If we can't open the file, it is not the same.  */
98           else
99             {
100               yes = (GetFileInformationByHandle (file1, &info1)
101                      && GetFileInformationByHandle (file2, &info2)
102                      && info1.dwVolumeSerialNumber==info2.dwVolumeSerialNumber
103                      && info1.nFileIndexHigh == info2.nFileIndexHigh
104                      && info1.nFileIndexLow == info2.nFileIndexLow);
105               CloseHandle (file2);
106             }
107           CloseHandle (file1);
108         }
109 #else /*!HAVE_W32_SYSTEM*/
110       struct stat info1, info2;
111
112       yes = (!stat (name1, &info1) && !stat (name2, &info2)
113              && info1.st_dev == info2.st_dev && info1.st_ino == info2.st_ino);
114 #endif /*!HAVE_W32_SYSTEM*/
115     }
116   return yes;
117 }
118
119
120 /*
121   timegm() is a GNU function that might not be available everywhere.
122   It's basically the inverse of gmtime() - you give it a struct tm,
123   and get back a time_t.  It differs from mktime() in that it handles
124   the case where the struct tm is UTC and the local environment isn't.
125
126   Note, that this replacement implementation might not be thread-safe!
127
128   Some BSDs don't handle the putenv("foo") case properly, so we use
129   unsetenv if the platform has it to remove environment variables.
130 */
131 #ifndef HAVE_TIMEGM
132 time_t
133 timegm (struct tm *tm)
134 {
135 #ifdef HAVE_W32_SYSTEM
136   /* This one is thread safe.  */
137   SYSTEMTIME st;
138   FILETIME ft;
139   unsigned long long cnsecs;
140
141   st.wYear   = tm->tm_year + 1900;
142   st.wMonth  = tm->tm_mon  + 1;
143   st.wDay    = tm->tm_mday;
144   st.wHour   = tm->tm_hour;
145   st.wMinute = tm->tm_min;
146   st.wSecond = tm->tm_sec;
147   st.wMilliseconds = 0; /* Not available.  */
148   st.wDayOfWeek = 0;    /* Ignored.  */
149
150   /* System time is UTC thus the conversion is pretty easy.  */
151   if (!SystemTimeToFileTime (&st, &ft))
152     {
153       gpg_err_set_errno (EINVAL);
154       return (time_t)(-1);
155     }
156
157   cnsecs = (((unsigned long long)ft.dwHighDateTime << 32)
158             | ft.dwLowDateTime);
159   cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01.  */
160   return (time_t)(cnsecs / 10000000ULL);
161
162 #else /* (Non thread safe implementation!) */
163
164   time_t answer;
165   char *zone;
166
167   zone=getenv("TZ");
168   putenv("TZ=UTC");
169   tzset();
170   answer=mktime(tm);
171   if(zone)
172     {
173       static char *old_zone;
174
175       if (!old_zone)
176         {
177           old_zone = malloc(3+strlen(zone)+1);
178           if (old_zone)
179             {
180               strcpy(old_zone,"TZ=");
181               strcat(old_zone,zone);
182             }
183         }
184       if (old_zone)
185         putenv (old_zone);
186     }
187   else
188     gnupg_unsetenv("TZ");
189
190   tzset();
191   return answer;
192 #endif
193 }
194 #endif /*!HAVE_TIMEGM*/