Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

staging: exfat: stop using 32-bit time_t

time_t suffers from overflow problems and should not be used.

In exfat, it is currently used in two open-coded time64_to_tm()
implementations. Changes those to use the existing function instead.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Link: https://lore.kernel.org/r/20190906150917.1025250-2-arnd@arndb.de
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Arnd Bergmann and committed by
Greg Kroah-Hartman
44f6b40c 26cf7660

+38 -126
+38 -126
drivers/staging/exfat/exfat_super.c
··· 53 53 static void exfat_write_super(struct super_block *sb); 54 54 55 55 #define UNIX_SECS_1980 315532800L 56 - 57 - #if BITS_PER_LONG == 64 58 56 #define UNIX_SECS_2108 4354819200L 59 - #endif 60 - 61 - /* days between 1.1.70 and 1.1.80 (2 leap days) */ 62 - #define DAYS_DELTA_DECADE (365 * 10 + 2) 63 - /* 120 (2100 - 1980) isn't leap year */ 64 - #define NO_LEAP_YEAR_2100 (120) 65 - #define IS_LEAP_YEAR(y) (!((y) & 0x3) && (y) != NO_LEAP_YEAR_2100) 66 - 67 - #define SECS_PER_MIN (60) 68 - #define SECS_PER_HOUR (60 * SECS_PER_MIN) 69 - #define SECS_PER_DAY (24 * SECS_PER_HOUR) 70 - 71 - #define MAKE_LEAP_YEAR(leap_year, year) \ 72 - do { \ 73 - if (unlikely(year > NO_LEAP_YEAR_2100)) \ 74 - leap_year = ((year + 3) / 4) - 1; \ 75 - else \ 76 - leap_year = ((year + 3) / 4); \ 77 - } while (0) 78 - 79 - /* Linear day numbers of the respective 1sts in non-leap years. */ 80 - static time_t accum_days_in_year[] = { 81 - /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */ 82 - 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 83 - }; 84 57 85 58 /* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */ 86 59 static void exfat_time_fat2unix(struct exfat_sb_info *sbi, 87 60 struct timespec64 *ts, struct date_time_t *tp) 88 61 { 89 - time_t year = tp->Year; 90 - time_t ld; 62 + ts->tv_sec = mktime64(tp->Year + 1980, tp->Month + 1, tp->Day, 63 + tp->Hour, tp->Minute, tp->Second); 91 64 92 - MAKE_LEAP_YEAR(ld, year); 93 - 94 - if (IS_LEAP_YEAR(year) && (tp->Month) > 2) 95 - ld++; 96 - 97 - ts->tv_sec = tp->Second + 98 - tp->Minute * SECS_PER_MIN + 99 - tp->Hour * SECS_PER_HOUR + 100 - (ld + accum_days_in_year[(tp->Month)] + 101 - (tp->Day - 1)) * SECS_PER_DAY + 102 - (year * 365 + DAYS_DELTA_DECADE) * SECS_PER_DAY + 103 - sys_tz.tz_minuteswest * SECS_PER_MIN; 104 - 105 - ts->tv_nsec = 0; 65 + ts->tv_nsec = tp->MilliSecond * NSEC_PER_MSEC; 106 66 } 107 67 108 68 /* Convert linear UNIX date to a FAT time/date pair. */ 109 69 static void exfat_time_unix2fat(struct exfat_sb_info *sbi, 110 70 struct timespec64 *ts, struct date_time_t *tp) 111 71 { 112 - time_t second = ts->tv_sec; 113 - time_t day, month, year; 114 - time_t ld; 72 + time64_t second = ts->tv_sec; 73 + struct tm tm; 115 74 116 - second -= sys_tz.tz_minuteswest * SECS_PER_MIN; 75 + time64_to_tm(second, 0, &tm); 117 76 118 - /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */ 119 77 if (second < UNIX_SECS_1980) { 120 - tp->Second = 0; 121 - tp->Minute = 0; 122 - tp->Hour = 0; 123 - tp->Day = 1; 124 - tp->Month = 1; 125 - tp->Year = 0; 78 + tp->MilliSecond = 0; 79 + tp->Second = 0; 80 + tp->Minute = 0; 81 + tp->Hour = 0; 82 + tp->Day = 1; 83 + tp->Month = 1; 84 + tp->Year = 0; 126 85 return; 127 86 } 128 - #if (BITS_PER_LONG == 64) 87 + 129 88 if (second >= UNIX_SECS_2108) { 130 - tp->Second = 59; 131 - tp->Minute = 59; 132 - tp->Hour = 23; 133 - tp->Day = 31; 134 - tp->Month = 12; 135 - tp->Year = 127; 89 + tp->MilliSecond = 999; 90 + tp->Second = 59; 91 + tp->Minute = 59; 92 + tp->Hour = 23; 93 + tp->Day = 31; 94 + tp->Month = 12; 95 + tp->Year = 127; 136 96 return; 137 97 } 138 - #endif 139 - day = second / SECS_PER_DAY - DAYS_DELTA_DECADE; 140 - year = day / 365; 141 - MAKE_LEAP_YEAR(ld, year); 142 - if (year * 365 + ld > day) 143 - year--; 144 98 145 - MAKE_LEAP_YEAR(ld, year); 146 - day -= year * 365 + ld; 147 - 148 - if (IS_LEAP_YEAR(year) && day == accum_days_in_year[3]) { 149 - month = 2; 150 - } else { 151 - if (IS_LEAP_YEAR(year) && day > accum_days_in_year[3]) 152 - day--; 153 - for (month = 1; month < 12; month++) { 154 - if (accum_days_in_year[month + 1] > day) 155 - break; 156 - } 157 - } 158 - day -= accum_days_in_year[month]; 159 - 160 - tp->Second = second % SECS_PER_MIN; 161 - tp->Minute = (second / SECS_PER_MIN) % 60; 162 - tp->Hour = (second / SECS_PER_HOUR) % 24; 163 - tp->Day = day + 1; 164 - tp->Month = month; 165 - tp->Year = year; 99 + tp->MilliSecond = ts->tv_nsec / NSEC_PER_MSEC; 100 + tp->Second = tm.tm_sec; 101 + tp->Minute = tm.tm_min; 102 + tp->Hour = tm.tm_hour; 103 + tp->Day = tm.tm_mday; 104 + tp->Month = tm.tm_mon + 1; 105 + tp->Year = tm.tm_year + 1900 - 1980; 166 106 } 167 107 168 108 struct timestamp_t *tm_current(struct timestamp_t *tp) 169 109 { 170 - struct timespec64 ts; 171 - time_t second, day, leap_day, month, year; 110 + time64_t second = ktime_get_real_seconds(); 111 + struct tm tm; 172 112 173 - ktime_get_real_ts64(&ts); 113 + time64_to_tm(second, 0, &tm); 174 114 175 - second = ts.tv_sec; 176 - second -= sys_tz.tz_minuteswest * SECS_PER_MIN; 177 - 178 - /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */ 179 115 if (second < UNIX_SECS_1980) { 180 116 tp->sec = 0; 181 117 tp->min = 0; ··· 121 185 tp->year = 0; 122 186 return tp; 123 187 } 124 - #if BITS_PER_LONG == 64 188 + 125 189 if (second >= UNIX_SECS_2108) { 126 190 tp->sec = 59; 127 191 tp->min = 59; ··· 131 195 tp->year = 127; 132 196 return tp; 133 197 } 134 - #endif 135 198 136 - day = second / SECS_PER_DAY - DAYS_DELTA_DECADE; 137 - year = day / 365; 138 - 139 - MAKE_LEAP_YEAR(leap_day, year); 140 - if (year * 365 + leap_day > day) 141 - year--; 142 - 143 - MAKE_LEAP_YEAR(leap_day, year); 144 - 145 - day -= year * 365 + leap_day; 146 - 147 - if (IS_LEAP_YEAR(year) && day == accum_days_in_year[3]) { 148 - month = 2; 149 - } else { 150 - if (IS_LEAP_YEAR(year) && day > accum_days_in_year[3]) 151 - day--; 152 - for (month = 1; month < 12; month++) { 153 - if (accum_days_in_year[month + 1] > day) 154 - break; 155 - } 156 - } 157 - day -= accum_days_in_year[month]; 158 - 159 - tp->sec = second % SECS_PER_MIN; 160 - tp->min = (second / SECS_PER_MIN) % 60; 161 - tp->hour = (second / SECS_PER_HOUR) % 24; 162 - tp->day = day + 1; 163 - tp->mon = month; 164 - tp->year = year; 199 + tp->sec = tm.tm_sec; 200 + tp->min = tm.tm_min; 201 + tp->hour = tm.tm_hour; 202 + tp->day = tm.tm_mday; 203 + tp->mon = tm.tm_mon + 1; 204 + tp->year = tm.tm_year + 1900 - 1980; 165 205 166 206 return tp; 167 207 }