1 /*
2  * ntfstime.h - NTFS time related functions.  Originated from the Linux-NTFS project.
3  *
4  * Copyright (c) 2005 Anton Altaparmakov
5  * Copyright (c) 2005 Yura Pakhuchiy
6  * Copyright (c) 2010 Jean-Pierre Andre
7  *
8  * This program/include file is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as published
10  * by the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program/include file is distributed in the hope that it will be
14  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
15  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program (in the main directory of the NTFS-3G
20  * distribution in the file COPYING); if not, write to the Free Software
21  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23 
24 #ifndef _NTFS_NTFSTIME_H
25 #define _NTFS_NTFSTIME_H
26 
27 #ifdef HAVE_TIME_H
28 #include <time.h>
29 #endif
30 #ifdef HAVE_SYS_STAT_H
31 #include <sys/stat.h>
32 #endif
33 #ifdef HAVE_GETTIMEOFDAY
34 #include <sys/time.h>
35 #endif
36 
37 #include "types.h"
38 
39 /*
40  * assume "struct timespec" is not defined if st_mtime is not defined
41  */
42 #if !defined(st_mtime) & !defined(__timespec_defined)
43 struct timespec {
44 	time_t tv_sec;
45 	long tv_nsec;
46 } ;
47 #endif
48 
49 /*
50  * There are four times more conversions of internal representation
51  * to ntfs representation than any other conversion, so the most
52  * efficient internal representation is ntfs representation
53  * (with low endianness)
54  */
55 typedef sle64 ntfs_time;
56 
57 #define NTFS_TIME_OFFSET ((s64)(369 * 365 + 89) * 24 * 3600 * 10000000)
58 
59 /**
60  * ntfs2timespec - Convert an NTFS time to Unix time
61  * @ntfs_time:  An NTFS time in 100ns units since 1601
62  *
63  * NTFS stores times as the number of 100ns intervals since January 1st 1601 at
64  * 00:00 UTC.  This system will not suffer from Y2K problems until ~57000AD.
65  *
66  * Return:  A Unix time (number of seconds since 1970, and nanoseconds)
67  */
68 static __inline__ struct timespec ntfs2timespec(ntfs_time ntfstime)
69 {
70 	struct timespec spec;
71 	s64 cputime;
72 
73 	cputime = sle64_to_cpu(ntfstime);
74 	spec.tv_sec = (cputime - (NTFS_TIME_OFFSET)) / 10000000;
75 	spec.tv_nsec = (cputime - (NTFS_TIME_OFFSET)
76 			- (s64)spec.tv_sec*10000000)*100;
77 		/* force zero nsec for overflowing dates */
78 	if ((spec.tv_nsec < 0) || (spec.tv_nsec > 999999999))
79 		spec.tv_nsec = 0;
80 	return (spec);
81 }
82 
83 /**
84  * timespec2ntfs - Convert Linux time to NTFS time
85  * @utc_time:  Linux time to convert to NTFS
86  *
87  * Convert the Linux time @utc_time to its corresponding NTFS time.
88  *
89  * Linux stores time in a long at present and measures it as the number of
90  * 1-second intervals since 1st January 1970, 00:00:00 UTC
91  * with a separated non-negative nanosecond value
92  *
93  * NTFS uses Microsoft's standard time format which is stored in a sle64 and is
94  * measured as the number of 100 nano-second intervals since 1st January 1601,
95  * 00:00:00 UTC.
96  *
97  * Return:  An NTFS time (100ns units since Jan 1601)
98  */
99 static __inline__ ntfs_time timespec2ntfs(struct timespec spec)
100 {
101 	s64 units;
102 
103 	units = (s64)spec.tv_sec * 10000000
104 				+ NTFS_TIME_OFFSET + spec.tv_nsec/100;
105 	return (cpu_to_sle64(units));
106 }
107 
108 /*
109  *		Return the current time in ntfs format
110  */
111 
112 static __inline__ ntfs_time ntfs_current_time(void)
113 {
114 	struct timespec now;
115 
116 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_SYS_CLOCK_GETTIME)
117 	clock_gettime(CLOCK_REALTIME, &now);
118 #elif defined(HAVE_GETTIMEOFDAY)
119 	struct timeval microseconds;
120 
121 	gettimeofday(&microseconds, (struct timezone*)NULL);
122 	now.tv_sec = microseconds.tv_sec;
123 	now.tv_nsec = microseconds.tv_usec*1000;
124 #else
125 	now.tv_sec = time((time_t*)NULL);
126 	now.tv_nsec = 0;
127 #endif
128 	return (timespec2ntfs(now));
129 }
130 
131 #endif /* _NTFS_NTFSTIME_H */
132