summaryrefslogtreecommitdiff
path: root/windows-NT/JmgStat.c
diff options
context:
space:
mode:
Diffstat (limited to 'windows-NT/JmgStat.c')
-rw-r--r--windows-NT/JmgStat.c214
1 files changed, 214 insertions, 0 deletions
diff --git a/windows-NT/JmgStat.c b/windows-NT/JmgStat.c
new file mode 100644
index 0000000..b339577
--- /dev/null
+++ b/windows-NT/JmgStat.c
@@ -0,0 +1,214 @@
+//
+// Original Authors: Jonathan M. Gilligan, Tony M. Hoyle
+//
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 2 of the License, or (at your
+// option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Modification History:
+// 18 May 2001, JMG -- First version
+
+#include <windows.h>
+#include <tchar.h>
+#include <time.h>
+#include <stdbool.h>
+
+#include "JmgStat.h"
+
+
+/* Tony Hoyle's function for testing whether a given volume uses UTC or
+ * local time to record file modification times
+ *
+ * Reproduced here with permission of Tony Hoyle.
+ *
+ * This code is copyright by Tony Hoyle and is licensed under the Gnu
+ * Public License. (See above)
+ *
+ * NTFS, HPFS, and OWFS store file times as UTC times.
+ * FAT stores file times as local time.
+ *
+ * INPUTS:
+ * LPCSTR name: fully qualified path
+ *
+ * OUTPUTS:
+ * Return true if the file system on the volume in question
+ * stores file times as UTC
+ */
+bool IsUTCVolume ( LPCTSTR name )
+{
+ _TCHAR szDrive[_MAX_DRIVE + 1] = _T("");
+ _TCHAR szFs[32]=_T("");
+ _tsplitpath(name, szDrive, NULL, NULL, NULL);
+
+ _tcscat(szDrive, _T("\\"));
+ GetVolumeInformation( szDrive, NULL, 0, NULL, NULL, NULL, szFs, 32 );
+ return ! ( _tcsicmp( szFs, _T("NTFS") )
+ && _tcsicmp( szFs, _T("HPFS") )
+ && _tcsicmp( szFs, _T("OWFS") ) );
+}
+
+/* Convert a file time to a Unix time_t structure. This function is as
+ * complicated as it is because it needs to ask what time system the
+ * filetime describes.
+ *
+ * INPUTS:
+ * const FILETIME * ft: A file time. It may be in UTC or in local
+ * time (see local_time, below, for details).
+ *
+ * time_t * ut: The destination for the converted time.
+ *
+ * bool local_time: TRUE if the time in *ft is in local time
+ * and I need to convert to a real UTC time.
+ *
+ * OUTPUTS:
+ * time_t * ut: Store the result in *ut.
+ */
+static bool FileTimeToUnixTime ( const FILETIME* ft, time_t* ut, bool local_time )
+{
+ bool success = FALSE;
+ if ( local_time )
+ {
+ struct tm atm;
+ SYSTEMTIME st;
+
+ success = FileTimeToSystemTime ( ft, &st );
+
+ /* Important: mktime looks at the tm_isdst field to determine
+ * whether to apply the DST correction. If this field is zero,
+ * then no DST is applied. If the field is one, then DST is
+ * applied. If the field is minus one, then DST is applied
+ * if the United States rule calls for it (DST starts at
+ * 02:00 on the first Sunday in April and ends at 02:00 on
+ * the last Sunday in October.
+ *
+ * If you are concerned about time zones that follow different
+ * rules, then you must either use GetTimeZoneInformation() to
+ * get your system's TIME_ZONE_INFO and use the information
+ * therein to figure out whether the time in question was in
+ * DST or not, or else use SystemTimeToTzSpecifiedLocalTime()
+ * to do the same.
+ *
+ * I haven't tried playing with SystemTimeToTzSpecifiedLocalTime()
+ * so I am nor sure how well it handles funky stuff.
+ */
+ atm.tm_sec = st.wSecond;
+ atm.tm_min = st.wMinute;
+ atm.tm_hour = st.wHour;
+ atm.tm_mday = st.wDay;
+ /* tm_mon is 0 based */
+ atm.tm_mon = st.wMonth - 1;
+ /* tm_year is 1900 based */
+ atm.tm_year = st.wYear>1900?st.wYear - 1900:st.wYear;
+ atm.tm_isdst = -1; /* see notes above */
+ *ut = mktime ( &atm );
+ }
+ else
+ {
+
+ /* FILETIME = number of 100-nanosecond ticks since midnight
+ * 1 Jan 1601 UTC. time_t = number of 1-second ticks since
+ * midnight 1 Jan 1970 UTC. To translate, we subtract a
+ * FILETIME representation of midnight, 1 Jan 1970 from the
+ * time in question and divide by the number of 100-ns ticks
+ * in one second.
+ */
+
+ /* One second = 10,000,000 * 100 nsec */
+ const ULONGLONG second = 10000000L;
+
+ SYSTEMTIME base_st =
+ {
+ 1970, /* wYear */
+ 1, /* wMonth */
+ 0, /* wDayOfWeek */
+ 1, /* wDay */
+ 0, /* wHour */
+ 0, /* wMinute */
+ 0, /* wSecond */
+ 0 /* wMilliseconds */
+ };
+
+ ULARGE_INTEGER itime;
+ FILETIME base_ft;
+
+ success = SystemTimeToFileTime ( &base_st, &base_ft );
+ if (success)
+ {
+ itime.QuadPart = ((ULARGE_INTEGER *)ft)->QuadPart;
+
+ itime.QuadPart -= ((ULARGE_INTEGER *)&base_ft)->QuadPart;
+ itime.QuadPart /= second;
+
+ *ut = itime.LowPart;
+ }
+ }
+ if (!success)
+ {
+ *ut = -1; /* error value used by mktime() */
+ }
+ return success;
+}
+
+/* Get file modification time using FileTimeToUnixTime()
+ *
+ * INPUTS:
+ * LPCTSTR name: the file name
+ */
+bool GetUTCFileModTime ( LPCTSTR name, time_t * utc_mod_time )
+{
+ WIN32_FIND_DATA find_buf;
+ FILETIME mod_time;
+ HANDLE find_handle;
+ bool success = FALSE;
+
+ * utc_mod_time = 0L;
+
+ find_handle = FindFirstFile ( name, &find_buf );
+ success = ( find_handle != INVALID_HANDLE_VALUE );
+ if (success)
+ {
+ /* Originally I thought that I needed to apply a correction
+ * LocalTimeToFileTime() to files from FAT volumes, but the
+ * FindFirstFile() system call thoughtfully applies this
+ * correction itself.
+ *
+ * Thus, the file time returned is allegedly in UTC.
+ *
+ * However, the correction from local to UTC is applied
+ * incorrectly (Thanks a lot, Microsoft!). As documented in the
+ * Win32 API (see MSDN or the PSDK), DST is applied if and only
+ * if the computer's system time is in DST at the time we call
+ * FindFirstFile(), irrespective or whether DST applied at the
+ * time the file was modified!
+ *
+ * Thus, we have to call FileTimeToLocalFileTime() to undo
+ * Windows's good intentions. We correctly translate the time
+ * In FileTimeToUnixTime().
+ *
+ */
+ if ( IsUTCVolume ( name ) )
+ {
+ mod_time = find_buf.ftLastWriteTime;
+ success = FileTimeToUnixTime ( &mod_time, utc_mod_time, FALSE );
+ }
+ else
+ {
+ // See notes above...
+ success = FileTimeToLocalFileTime ( &find_buf.ftLastWriteTime, &mod_time );
+ success = success && FileTimeToUnixTime ( &mod_time, utc_mod_time, TRUE );
+ }
+ }
+ FindClose ( find_handle );
+ return success;
+}