162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  linux/fs/isofs/util.c
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/time.h>
762306a36Sopenharmony_ci#include "isofs.h"
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci/*
1062306a36Sopenharmony_ci * We have to convert from a MM/DD/YY format to the Unix ctime format.
1162306a36Sopenharmony_ci * We have to take into account leap years and all of that good stuff.
1262306a36Sopenharmony_ci * Unfortunately, the kernel does not have the information on hand to
1362306a36Sopenharmony_ci * take into account daylight savings time, but it shouldn't matter.
1462306a36Sopenharmony_ci * The time stored should be localtime (with or without DST in effect),
1562306a36Sopenharmony_ci * and the timezone offset should hold the offset required to get back
1662306a36Sopenharmony_ci * to GMT.  Thus  we should always be correct.
1762306a36Sopenharmony_ci */
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ciint iso_date(u8 *p, int flag)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	int year, month, day, hour, minute, second, tz;
2262306a36Sopenharmony_ci	int crtime;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	year = p[0];
2562306a36Sopenharmony_ci	month = p[1];
2662306a36Sopenharmony_ci	day = p[2];
2762306a36Sopenharmony_ci	hour = p[3];
2862306a36Sopenharmony_ci	minute = p[4];
2962306a36Sopenharmony_ci	second = p[5];
3062306a36Sopenharmony_ci	if (flag == 0) tz = p[6]; /* High sierra has no time zone */
3162306a36Sopenharmony_ci	else tz = 0;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	if (year < 0) {
3462306a36Sopenharmony_ci		crtime = 0;
3562306a36Sopenharmony_ci	} else {
3662306a36Sopenharmony_ci		crtime = mktime64(year+1900, month, day, hour, minute, second);
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci		/* sign extend */
3962306a36Sopenharmony_ci		if (tz & 0x80)
4062306a36Sopenharmony_ci			tz |= (-1 << 8);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci		/*
4362306a36Sopenharmony_ci		 * The timezone offset is unreliable on some disks,
4462306a36Sopenharmony_ci		 * so we make a sanity check.  In no case is it ever
4562306a36Sopenharmony_ci		 * more than 13 hours from GMT, which is 52*15min.
4662306a36Sopenharmony_ci		 * The time is always stored in localtime with the
4762306a36Sopenharmony_ci		 * timezone offset being what get added to GMT to
4862306a36Sopenharmony_ci		 * get to localtime.  Thus we need to subtract the offset
4962306a36Sopenharmony_ci		 * to get to true GMT, which is what we store the time
5062306a36Sopenharmony_ci		 * as internally.  On the local system, the user may set
5162306a36Sopenharmony_ci		 * their timezone any way they wish, of course, so GMT
5262306a36Sopenharmony_ci		 * gets converted back to localtime on the receiving
5362306a36Sopenharmony_ci		 * system.
5462306a36Sopenharmony_ci		 *
5562306a36Sopenharmony_ci		 * NOTE: mkisofs in versions prior to mkisofs-1.10 had
5662306a36Sopenharmony_ci		 * the sign wrong on the timezone offset.  This has now
5762306a36Sopenharmony_ci		 * been corrected there too, but if you are getting screwy
5862306a36Sopenharmony_ci		 * results this may be the explanation.  If enough people
5962306a36Sopenharmony_ci		 * complain, a user configuration option could be added
6062306a36Sopenharmony_ci		 * to add the timezone offset in with the wrong sign
6162306a36Sopenharmony_ci		 * for 'compatibility' with older discs, but I cannot see how
6262306a36Sopenharmony_ci		 * it will matter that much.
6362306a36Sopenharmony_ci		 *
6462306a36Sopenharmony_ci		 * Thanks to kuhlmav@elec.canterbury.ac.nz (Volker Kuhlmann)
6562306a36Sopenharmony_ci		 * for pointing out the sign error.
6662306a36Sopenharmony_ci		 */
6762306a36Sopenharmony_ci		if (-52 <= tz && tz <= 52)
6862306a36Sopenharmony_ci			crtime -= tz * 15 * 60;
6962306a36Sopenharmony_ci	}
7062306a36Sopenharmony_ci	return crtime;
7162306a36Sopenharmony_ci}
72