Coverage Report

Created: 2026-09-14 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Utilities/cmlibarchive/libarchive/archive_time.c
Line
Count
Source
1
/*-
2
 * Copyright © 2025 ARJANEN Loïc Jean David
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 *
14
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
 */
25
26
#include "archive_platform.h"
27
28
#ifdef HAVE_LIMITS_H
29
#include <limits.h>
30
#endif
31
#ifdef HAVE_STDLIB_H
32
#include <stdlib.h>
33
#endif
34
#ifdef HAVE_STRING_H
35
#include <string.h>
36
#endif
37
38
#include "archive_integer.h"
39
#include "archive_private.h"
40
#include "archive_time_private.h"
41
42
2.92k
#define NTFS_EPOC_TIME ARCHIVE_LITERAL_ULL(11644473600)
43
6.58k
#define NTFS_TICKS ARCHIVE_LITERAL_ULL(10000000)
44
2.92k
#define NTFS_EPOC_TICKS (NTFS_EPOC_TIME * NTFS_TICKS)
45
0
#define DOS_MIN_TIME 0x00210000U
46
0
#define DOS_MAX_TIME 0xff9fbf7dU
47
48
#if defined(_WIN32) && !defined(__CYGWIN__)
49
#include <winnt.h>
50
/* Windows FILETIME to NTFS time. */
51
uint64_t
52
FILETIME_to_ntfs(const FILETIME* filetime)
53
{
54
  ULARGE_INTEGER utc;
55
  utc.HighPart = filetime->dwHighDateTime;
56
  utc.LowPart  = filetime->dwLowDateTime;
57
  return utc.QuadPart;
58
}
59
#endif
60
61
/* Convert an MSDOS-style date/time into Unix-style time. */
62
int64_t
63
dos_to_unix(uint32_t dos_time)
64
50.1k
{
65
50.1k
  uint16_t msTime, msDate;
66
50.1k
  struct tm ts;
67
50.1k
  time_t t;
68
69
50.1k
  msTime = (0xFFFF & dos_time);
70
50.1k
  msDate = (dos_time >> 16);
71
72
50.1k
  memset(&ts, 0, sizeof(ts));
73
50.1k
  ts.tm_year = ((msDate >> 9) & 0x7f) + 80; /* Years since 1900. */
74
50.1k
  ts.tm_mon = ((msDate >> 5) & 0x0f) - 1; /* Month number. */
75
50.1k
  ts.tm_mday = msDate & 0x1f; /* Day of month. */
76
50.1k
  ts.tm_hour = (msTime >> 11) & 0x1f;
77
50.1k
  ts.tm_min = (msTime >> 5) & 0x3f;
78
50.1k
  ts.tm_sec = (msTime << 1) & 0x3e;
79
50.1k
  ts.tm_isdst = -1;
80
50.1k
  t = mktime(&ts);
81
50.1k
  return (int64_t)(t == (time_t)-1 ? INT32_MAX : t);
82
50.1k
}
83
84
/* Convert into MSDOS-style date/time. */
85
uint32_t
86
unix_to_dos(int64_t unix_time)
87
0
{
88
0
  struct tm *t;
89
0
  uint32_t dt;
90
0
  time_t ut = unix_time;
91
0
#if defined(HAVE_LOCALTIME_R) || defined(HAVE_LOCALTIME_S)
92
0
  struct tm tmbuf;
93
0
#endif
94
95
0
  if (sizeof(time_t) < sizeof(int64_t) && (int64_t)ut != unix_time) {
96
0
    ut = (time_t)(unix_time > 0 ? INT32_MAX : INT32_MIN);
97
0
  }
98
99
#if defined(HAVE_LOCALTIME_S)
100
  t = localtime_s(&tmbuf, &ut) ? NULL : &tmbuf;
101
#elif defined(HAVE_LOCALTIME_R)
102
  t = localtime_r(&ut, &tmbuf);
103
#else
104
  t = localtime(&ut);
105
#endif
106
0
  dt = 0;
107
0
  if (t != NULL && t->tm_year >= INT_MIN + 80) {
108
0
    const int year = t->tm_year - 80;
109
110
0
    if (year & ~0x7f) {
111
0
      dt = year > 0 ? DOS_MAX_TIME : DOS_MIN_TIME;
112
0
    }
113
0
    else {
114
0
      dt += (year & 0x7f) << 9;
115
0
      dt += ((t->tm_mon + 1) & 0x0f) << 5;
116
0
      dt += (t->tm_mday & 0x1f);
117
0
      dt <<= 16;
118
0
      dt += (t->tm_hour & 0x1f) << 11;
119
0
      dt += (t->tm_min & 0x3f) << 5;
120
      /* Only counting every 2 seconds. */
121
0
      dt += (t->tm_sec & 0x3e) >> 1;
122
0
    }
123
0
  }
124
0
  if (dt > DOS_MAX_TIME) {
125
0
    dt = DOS_MAX_TIME;
126
0
  }
127
0
  else if (dt < DOS_MIN_TIME) {
128
0
    dt = DOS_MIN_TIME;
129
0
  }
130
0
  return dt;
131
0
}
132
133
/* Convert NTFS time to Unix sec/nsec */
134
void
135
ntfs_to_unix(uint64_t ntfs, int64_t* secs, uint32_t* nsecs)
136
2.92k
{
137
2.92k
  if (ntfs > INT64_MAX) {
138
726
    ntfs -= NTFS_EPOC_TICKS;
139
726
    *secs = ntfs / NTFS_TICKS;
140
726
    *nsecs = 100 * (ntfs % NTFS_TICKS);
141
726
  }
142
2.20k
  else {
143
2.20k
    lldiv_t tdiv;
144
2.20k
    int64_t value = (int64_t)ntfs - (int64_t)NTFS_EPOC_TICKS;
145
146
2.20k
    tdiv = lldiv(value, NTFS_TICKS);
147
2.20k
    *secs = tdiv.quot;
148
2.20k
    *nsecs = (uint32_t)(tdiv.rem * 100);
149
2.20k
  }
150
2.92k
}
151
152
/* Convert Unix sec/nsec to NTFS time */
153
uint64_t
154
unix_to_ntfs(int64_t secs, uint32_t nsecs)
155
0
{
156
0
  uint64_t ntfs;
157
158
0
  if (secs < -(int64_t)NTFS_EPOC_TIME)
159
0
    return 0;
160
161
  /* (secs + NTFS_EPOC_TIME) * NTFS_TICKS + nsecs / 100 */
162
0
  if (archive_ckd_add_u64(&ntfs, secs, NTFS_EPOC_TIME) ||
163
0
      archive_ckd_mul_u64(&ntfs, ntfs, NTFS_TICKS) ||
164
0
      archive_ckd_add_u64(&ntfs, ntfs, nsecs / 100))
165
0
    return UINT64_MAX;
166
167
0
  return ntfs;
168
0
}