1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Written 1992,1993 by Werner Almesberger
4 * 22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980
5 * and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru)
6 * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
9 #include <linux/time.h>
11 #include <linux/slab.h>
12 #include <linux/buffer_head.h>
13 #include <linux/blk_types.h>
15 #include "exfat_raw.h"
19 * exfat_fs_error reports a file system problem that might indicate fa data
20 * corruption/inconsistency. Depending on 'errors' mount option the
21 * panic() is called, or error message is printed FAT and nothing is done,
22 * or filesystem is remounted read-only (default behavior).
23 * In case the file system is remounted read-only, it can be made writable
24 * again by remounting it.
26 void __exfat_fs_error(struct super_block
*sb
, int report
, const char *fmt
, ...)
28 struct exfat_mount_options
*opts
= &EXFAT_SB(sb
)->options
;
36 exfat_err(sb
, "error, %pV", &vaf
);
40 if (opts
->errors
== EXFAT_ERRORS_PANIC
) {
41 panic("exFAT-fs (%s): fs panic from previous error\n",
43 } else if (opts
->errors
== EXFAT_ERRORS_RO
&& !sb_rdonly(sb
)) {
44 sb
->s_flags
|= SB_RDONLY
;
45 exfat_err(sb
, "Filesystem has been set read-only");
49 #define SECS_PER_MIN (60)
50 #define TIMEZONE_SEC(x) ((x) * 15 * SECS_PER_MIN)
52 static void exfat_adjust_tz(struct timespec64
*ts
, u8 tz_off
)
55 ts
->tv_sec
-= TIMEZONE_SEC(tz_off
);
56 else /* 0x40 <= (tz_off & 0x7F) <=0x7F */
57 ts
->tv_sec
+= TIMEZONE_SEC(0x80 - tz_off
);
60 static inline int exfat_tz_offset(struct exfat_sb_info
*sbi
)
62 if (sbi
->options
.sys_tz
)
63 return -sys_tz
.tz_minuteswest
;
64 return sbi
->options
.time_offset
;
67 /* Convert a EXFAT time/date pair to a UNIX date (seconds since 1 1 70). */
68 void exfat_get_entry_time(struct exfat_sb_info
*sbi
, struct timespec64
*ts
,
69 u8 tz
, __le16 time
, __le16 date
, u8 time_cs
)
71 u16 t
= le16_to_cpu(time
);
72 u16 d
= le16_to_cpu(date
);
74 ts
->tv_sec
= mktime64(1980 + (d
>> 9), d
>> 5 & 0x000F, d
& 0x001F,
75 t
>> 11, (t
>> 5) & 0x003F, (t
& 0x001F) << 1);
78 /* time_cs field represent 0 ~ 199cs(1990 ms) */
80 ts
->tv_sec
+= time_cs
/ 100;
81 ts
->tv_nsec
= (time_cs
% 100) * 10 * NSEC_PER_MSEC
;
85 if (tz
& EXFAT_TZ_VALID
)
86 /* Adjust timezone to UTC0. */
87 exfat_adjust_tz(ts
, tz
& ~EXFAT_TZ_VALID
);
89 ts
->tv_sec
-= exfat_tz_offset(sbi
) * SECS_PER_MIN
;
92 /* Convert linear UNIX date to a EXFAT time/date pair. */
93 void exfat_set_entry_time(struct exfat_sb_info
*sbi
, struct timespec64
*ts
,
94 u8
*tz
, __le16
*time
, __le16
*date
, u8
*time_cs
)
99 time64_to_tm(ts
->tv_sec
, 0, &tm
);
100 t
= (tm
.tm_hour
<< 11) | (tm
.tm_min
<< 5) | (tm
.tm_sec
>> 1);
101 d
= ((tm
.tm_year
- 80) << 9) | ((tm
.tm_mon
+ 1) << 5) | tm
.tm_mday
;
103 *time
= cpu_to_le16(t
);
104 *date
= cpu_to_le16(d
);
106 /* time_cs field represent 0 ~ 199cs(1990 ms) */
108 *time_cs
= (tm
.tm_sec
& 1) * 100 +
109 ts
->tv_nsec
/ (10 * NSEC_PER_MSEC
);
112 * Record 00h value for OffsetFromUtc field and 1 value for OffsetValid
113 * to indicate that local time and UTC are the same.
115 *tz
= EXFAT_TZ_VALID
;
119 * The timestamp for access_time has double seconds granularity.
120 * (There is no 10msIncrement field for access_time unlike create/modify_time)
121 * atime also has only a 2-second resolution.
123 void exfat_truncate_atime(struct timespec64
*ts
)
125 ts
->tv_sec
= round_down(ts
->tv_sec
, 2);
129 void exfat_truncate_inode_atime(struct inode
*inode
)
131 struct timespec64 atime
= inode_get_atime(inode
);
133 exfat_truncate_atime(&atime
);
134 inode_set_atime_to_ts(inode
, atime
);
137 u16
exfat_calc_chksum16(void *data
, int len
, u16 chksum
, int type
)
142 for (i
= 0; i
< len
; i
++, c
++) {
143 if (unlikely(type
== CS_DIR_ENTRY
&& (i
== 2 || i
== 3)))
145 chksum
= ((chksum
<< 15) | (chksum
>> 1)) + *c
;
150 u32
exfat_calc_chksum32(void *data
, int len
, u32 chksum
, int type
)
155 for (i
= 0; i
< len
; i
++, c
++) {
156 if (unlikely(type
== CS_BOOT_SECTOR
&&
157 (i
== 106 || i
== 107 || i
== 112)))
159 chksum
= ((chksum
<< 31) | (chksum
>> 1)) + *c
;
164 void exfat_update_bh(struct buffer_head
*bh
, int sync
)
166 set_buffer_uptodate(bh
);
167 mark_buffer_dirty(bh
);
170 sync_dirty_buffer(bh
);
173 int exfat_update_bhs(struct buffer_head
**bhs
, int nr_bhs
, int sync
)
177 for (i
= 0; i
< nr_bhs
; i
++) {
178 set_buffer_uptodate(bhs
[i
]);
179 mark_buffer_dirty(bhs
[i
]);
181 write_dirty_buffer(bhs
[i
], REQ_SYNC
);
184 for (i
= 0; i
< nr_bhs
&& sync
; i
++) {
185 wait_on_buffer(bhs
[i
]);
186 if (!err
&& !buffer_uptodate(bhs
[i
]))
192 void exfat_chain_set(struct exfat_chain
*ec
, unsigned int dir
,
193 unsigned int size
, unsigned char flags
)
200 void exfat_chain_dup(struct exfat_chain
*dup
, struct exfat_chain
*ec
)
202 return exfat_chain_set(dup
, ec
->dir
, ec
->size
, ec
->flags
);