@@ -29,6 +29,22 @@ struct fat_timestamp_testcase {
2929 int time_offset ;
3030};
3131
32+ struct fat_unix2fat_clamp_testcase {
33+ const char * name ;
34+ struct timespec64 ts ;
35+ __le16 time ;
36+ __le16 date ;
37+ u8 cs ;
38+ int time_offset ;
39+ };
40+
41+ struct fat_truncate_atime_testcase {
42+ const char * name ;
43+ struct timespec64 ts ;
44+ struct timespec64 expected ;
45+ int time_offset ;
46+ };
47+
3248static struct fat_timestamp_testcase time_test_cases [] = {
3349 {
3450 .name = "Earliest possible UTC (1980-01-01 00:00:00)" ,
@@ -120,13 +136,92 @@ static struct fat_timestamp_testcase time_test_cases[] = {
120136 },
121137};
122138
139+ static struct fat_unix2fat_clamp_testcase unix2fat_clamp_test_cases [] = {
140+ {
141+ .name = "Clamp to earliest FAT date for 1979-12-31 23:59:59 UTC" ,
142+ .ts = {.tv_sec = 315532799LL , .tv_nsec = 0L },
143+ .time = cpu_to_le16 (0 ),
144+ .date = cpu_to_le16 (33 ),
145+ .cs = 0 ,
146+ .time_offset = 0 ,
147+ },
148+ {
149+ .name = "Clamp after time_offset=-60 pushes 1980-01-01 00:30 UTC below 1980" ,
150+ .ts = {.tv_sec = 315534600LL , .tv_nsec = 0L },
151+ .time = cpu_to_le16 (0 ),
152+ .date = cpu_to_le16 (33 ),
153+ .cs = 0 ,
154+ .time_offset = -60 ,
155+ },
156+ {
157+ .name = "Clamp to latest FAT date for 2108-01-01 00:00:00 UTC" ,
158+ .ts = {.tv_sec = 4354819200LL , .tv_nsec = 0L },
159+ .time = cpu_to_le16 (49021 ),
160+ .date = cpu_to_le16 (65439 ),
161+ .cs = 199 ,
162+ .time_offset = 0 ,
163+ },
164+ {
165+ .name = "Clamp after time_offset=60 pushes 2107-12-31 23:30 UTC beyond 2107" ,
166+ .ts = {.tv_sec = 4354817400LL , .tv_nsec = 0L },
167+ .time = cpu_to_le16 (49021 ),
168+ .date = cpu_to_le16 (65439 ),
169+ .cs = 199 ,
170+ .time_offset = 60 ,
171+ },
172+ };
173+
174+ static struct fat_truncate_atime_testcase truncate_atime_test_cases [] = {
175+ {
176+ .name = "UTC atime truncates to 2004-02-29 00:00:00" ,
177+ .ts = {.tv_sec = 1078058096LL , .tv_nsec = 789000000L },
178+ .expected = {.tv_sec = 1078012800LL , .tv_nsec = 0L },
179+ .time_offset = 0 ,
180+ },
181+ {
182+ .name = "time_offset=-60 truncates 2004-02-29 00:30 UTC to previous local midnight" ,
183+ .ts = {.tv_sec = 1078014645LL , .tv_nsec = 123000000L },
184+ .expected = {.tv_sec = 1077930000LL , .tv_nsec = 0L },
185+ .time_offset = -60 ,
186+ },
187+ {
188+ .name = "time_offset=60 truncates 2004-02-29 23:30 UTC to next local midnight" ,
189+ .ts = {.tv_sec = 1078097445LL , .tv_nsec = 123000000L },
190+ .expected = {.tv_sec = 1078095600LL , .tv_nsec = 0L },
191+ .time_offset = 60 ,
192+ },
193+ };
194+
123195static void time_testcase_desc (struct fat_timestamp_testcase * t ,
124196 char * desc )
125197{
126198 strscpy (desc , t -> name , KUNIT_PARAM_DESC_SIZE );
127199}
128200
201+ static void unix2fat_clamp_testcase_desc (struct fat_unix2fat_clamp_testcase * t ,
202+ char * desc )
203+ {
204+ strscpy (desc , t -> name , KUNIT_PARAM_DESC_SIZE );
205+ }
206+
207+ static void truncate_atime_testcase_desc (struct fat_truncate_atime_testcase * t ,
208+ char * desc )
209+ {
210+ strscpy (desc , t -> name , KUNIT_PARAM_DESC_SIZE );
211+ }
212+
129213KUNIT_ARRAY_PARAM (fat_time , time_test_cases , time_testcase_desc );
214+ KUNIT_ARRAY_PARAM (fat_unix2fat_clamp , unix2fat_clamp_test_cases ,
215+ unix2fat_clamp_testcase_desc );
216+ KUNIT_ARRAY_PARAM (fat_truncate_atime , truncate_atime_test_cases ,
217+ truncate_atime_testcase_desc );
218+
219+ static void fat_test_set_time_offset (struct msdos_sb_info * sbi , int time_offset )
220+ {
221+ memset (sbi , 0 , sizeof (* sbi ));
222+ sbi -> options .tz_set = 1 ;
223+ sbi -> options .time_offset = time_offset ;
224+ }
130225
131226static void fat_time_fat2unix_test (struct kunit * test )
132227{
@@ -135,8 +230,7 @@ static void fat_time_fat2unix_test(struct kunit *test)
135230 struct fat_timestamp_testcase * testcase =
136231 (struct fat_timestamp_testcase * )test -> param_value ;
137232
138- fake_sb .options .tz_set = 1 ;
139- fake_sb .options .time_offset = testcase -> time_offset ;
233+ fat_test_set_time_offset (& fake_sb , testcase -> time_offset );
140234
141235 fat_time_fat2unix (& fake_sb , & ts ,
142236 testcase -> time ,
@@ -160,29 +254,100 @@ static void fat_time_unix2fat_test(struct kunit *test)
160254 struct fat_timestamp_testcase * testcase =
161255 (struct fat_timestamp_testcase * )test -> param_value ;
162256
163- fake_sb .options .tz_set = 1 ;
164- fake_sb .options .time_offset = testcase -> time_offset ;
257+ fat_test_set_time_offset (& fake_sb , testcase -> time_offset );
165258
166259 fat_time_unix2fat (& fake_sb , & testcase -> ts ,
167260 & time , & date , & cs );
168261 KUNIT_EXPECT_EQ_MSG (test ,
169- le16_to_cpu ( testcase -> time ) ,
170- le16_to_cpu ( time ) ,
262+ testcase -> time ,
263+ time ,
171264 "Time mismatch\n" );
172265 KUNIT_EXPECT_EQ_MSG (test ,
173- le16_to_cpu ( testcase -> date ) ,
174- le16_to_cpu ( date ) ,
266+ testcase -> date ,
267+ date ,
175268 "Date mismatch\n" );
176269 KUNIT_EXPECT_EQ_MSG (test ,
177270 testcase -> cs ,
178271 cs ,
179272 "Centisecond mismatch\n" );
180273}
181274
275+ static void fat_time_unix2fat_clamp_test (struct kunit * test )
276+ {
277+ static struct msdos_sb_info fake_sb ;
278+ __le16 date , time ;
279+ u8 cs ;
280+ struct fat_unix2fat_clamp_testcase * testcase =
281+ (struct fat_unix2fat_clamp_testcase * )test -> param_value ;
282+
283+ fat_test_set_time_offset (& fake_sb , testcase -> time_offset );
284+
285+ fat_time_unix2fat (& fake_sb , & testcase -> ts , & time , & date , & cs );
286+ KUNIT_EXPECT_EQ_MSG (test ,
287+ testcase -> time ,
288+ time ,
289+ "Clamped time mismatch\n" );
290+ KUNIT_EXPECT_EQ_MSG (test ,
291+ testcase -> date ,
292+ date ,
293+ "Clamped date mismatch\n" );
294+ KUNIT_EXPECT_EQ_MSG (test ,
295+ testcase -> cs ,
296+ cs ,
297+ "Clamped centisecond mismatch\n" );
298+ }
299+
300+ static void fat_time_unix2fat_no_csec_test (struct kunit * test )
301+ {
302+ static struct msdos_sb_info fake_sb ;
303+ struct timespec64 ts = {
304+ .tv_sec = 946684799LL ,
305+ .tv_nsec = 0L ,
306+ };
307+ __le16 date , time ;
308+
309+ fat_test_set_time_offset (& fake_sb , 0 );
310+
311+ fat_time_unix2fat (& fake_sb , & ts , & time , & date , NULL );
312+ KUNIT_EXPECT_EQ_MSG (test ,
313+ 49021 ,
314+ le16_to_cpu (time ),
315+ "Time mismatch without centiseconds\n" );
316+ KUNIT_EXPECT_EQ_MSG (test ,
317+ 10143 ,
318+ le16_to_cpu (date ),
319+ "Date mismatch without centiseconds\n" );
320+ }
321+
322+ static void fat_truncate_atime_test (struct kunit * test )
323+ {
324+ static struct msdos_sb_info fake_sb ;
325+ struct timespec64 actual ;
326+ struct fat_truncate_atime_testcase * testcase =
327+ (struct fat_truncate_atime_testcase * )test -> param_value ;
328+
329+ fat_test_set_time_offset (& fake_sb , testcase -> time_offset );
330+
331+ actual = fat_truncate_atime (& fake_sb , & testcase -> ts );
332+ KUNIT_EXPECT_EQ_MSG (test ,
333+ testcase -> expected .tv_sec ,
334+ actual .tv_sec ,
335+ "Atime truncation seconds mismatch\n" );
336+ KUNIT_EXPECT_EQ_MSG (test ,
337+ testcase -> expected .tv_nsec ,
338+ actual .tv_nsec ,
339+ "Atime truncation nanoseconds mismatch\n" );
340+ }
341+
182342static struct kunit_case fat_test_cases [] = {
183343 KUNIT_CASE (fat_checksum_test ),
184344 KUNIT_CASE_PARAM (fat_time_fat2unix_test , fat_time_gen_params ),
185345 KUNIT_CASE_PARAM (fat_time_unix2fat_test , fat_time_gen_params ),
346+ KUNIT_CASE_PARAM (fat_time_unix2fat_clamp_test ,
347+ fat_unix2fat_clamp_gen_params ),
348+ KUNIT_CASE (fat_time_unix2fat_no_csec_test ),
349+ KUNIT_CASE_PARAM (fat_truncate_atime_test ,
350+ fat_truncate_atime_gen_params ),
186351 {},
187352};
188353
0 commit comments