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>
14 #include "exfat_raw.h"
18 * exfat_fs_error reports a file system problem that might indicate fa data
19 * corruption/inconsistency. Depending on 'errors' mount option the
20 * panic() is called, or error message is printed FAT and nothing is done,
21 * or filesystem is remounted read-only (default behavior).
22 * In case the file system is remounted read-only, it can be made writable
23 * again by remounting it.
25 void __exfat_fs_error(struct super_block
*sb
, int report
, const char *fmt
, ...)
27 struct exfat_mount_options
*opts
= &EXFAT_SB(sb
)->options
;
35 exfat_msg(sb
, KERN_ERR
, "error, %pV\n", &vaf
);
39 if (opts
->errors
== EXFAT_ERRORS_PANIC
) {
40 panic("exFAT-fs (%s): fs panic from previous error\n",
42 } else if (opts
->errors
== EXFAT_ERRORS_RO
&& !sb_rdonly(sb
)) {
43 sb
->s_flags
|= SB_RDONLY
;
44 exfat_msg(sb
, KERN_ERR
, "Filesystem has been set read-only");
49 * exfat_msg() - print preformated EXFAT specific messages.
50 * All logs except what uses exfat_fs_error() should be written by exfat_msg()
52 void exfat_msg(struct super_block
*sb
, const char *level
, const char *fmt
, ...)
60 /* level means KERN_ pacility level */
61 printk("%sexFAT-fs (%s): %pV\n", level
, sb
->s_id
, &vaf
);
65 #define SECS_PER_MIN (60)
66 #define TIMEZONE_SEC(x) ((x) * 15 * SECS_PER_MIN)
68 static void exfat_adjust_tz(struct timespec64
*ts
, u8 tz_off
)
71 ts
->tv_sec
-= TIMEZONE_SEC(tz_off
);
72 else /* 0x40 <= (tz_off & 0x7F) <=0x7F */
73 ts
->tv_sec
+= TIMEZONE_SEC(0x80 - tz_off
);
76 /* Convert a EXFAT time/date pair to a UNIX date (seconds since 1 1 70). */
77 void exfat_get_entry_time(struct exfat_sb_info
*sbi
, struct timespec64
*ts
,
78 u8 tz
, __le16 time
, __le16 date
, u8 time_ms
)
80 u16 t
= le16_to_cpu(time
);
81 u16 d
= le16_to_cpu(date
);
83 ts
->tv_sec
= mktime64(1980 + (d
>> 9), d
>> 5 & 0x000F, d
& 0x001F,
84 t
>> 11, (t
>> 5) & 0x003F, (t
& 0x001F) << 1);
87 /* time_ms field represent 0 ~ 199(1990 ms) */
89 ts
->tv_sec
+= time_ms
/ 100;
90 ts
->tv_nsec
= (time_ms
% 100) * 10 * NSEC_PER_MSEC
;
94 if (tz
& EXFAT_TZ_VALID
)
95 /* Adjust timezone to UTC0. */
96 exfat_adjust_tz(ts
, tz
& ~EXFAT_TZ_VALID
);
98 /* Convert from local time to UTC using time_offset. */
99 ts
->tv_sec
-= sbi
->options
.time_offset
* SECS_PER_MIN
;
102 /* Convert linear UNIX date to a EXFAT time/date pair. */
103 void exfat_set_entry_time(struct exfat_sb_info
*sbi
, struct timespec64
*ts
,
104 u8
*tz
, __le16
*time
, __le16
*date
, u8
*time_ms
)
109 time64_to_tm(ts
->tv_sec
, 0, &tm
);
110 t
= (tm
.tm_hour
<< 11) | (tm
.tm_min
<< 5) | (tm
.tm_sec
>> 1);
111 d
= ((tm
.tm_year
- 80) << 9) | ((tm
.tm_mon
+ 1) << 5) | tm
.tm_mday
;
113 *time
= cpu_to_le16(t
);
114 *date
= cpu_to_le16(d
);
116 /* time_ms field represent 0 ~ 199(1990 ms) */
118 *time_ms
= (tm
.tm_sec
& 1) * 100 +
119 ts
->tv_nsec
/ (10 * NSEC_PER_MSEC
);
122 * Record 00h value for OffsetFromUtc field and 1 value for OffsetValid
123 * to indicate that local time and UTC are the same.
125 *tz
= EXFAT_TZ_VALID
;
129 * The timestamp for access_time has double seconds granularity.
130 * (There is no 10msIncrement field for access_time unlike create/modify_time)
131 * atime also has only a 2-second resolution.
133 void exfat_truncate_atime(struct timespec64
*ts
)
135 ts
->tv_sec
= round_down(ts
->tv_sec
, 2);
139 unsigned short exfat_calc_chksum_2byte(void *data
, int len
,
140 unsigned short chksum
, int type
)
143 unsigned char *c
= (unsigned char *)data
;
145 for (i
= 0; i
< len
; i
++, c
++) {
146 if (((i
== 2) || (i
== 3)) && (type
== CS_DIR_ENTRY
))
148 chksum
= (((chksum
& 1) << 15) | ((chksum
& 0xFFFE) >> 1)) +
154 void exfat_update_bh(struct super_block
*sb
, struct buffer_head
*bh
, int sync
)
156 set_bit(EXFAT_SB_DIRTY
, &EXFAT_SB(sb
)->s_state
);
157 set_buffer_uptodate(bh
);
158 mark_buffer_dirty(bh
);
161 sync_dirty_buffer(bh
);
164 void exfat_chain_set(struct exfat_chain
*ec
, unsigned int dir
,
165 unsigned int size
, unsigned char flags
)
172 void exfat_chain_dup(struct exfat_chain
*dup
, struct exfat_chain
*ec
)
174 return exfat_chain_set(dup
, ec
->dir
, ec
->size
, ec
->flags
);