Make msdosfs time conversion use the y/m/d/h/m/s conversion functions

from clock_subr.c and compile that into the userland (and tools)
makefs as well.
This commit is contained in:
martin 2014-09-01 09:09:47 +00:00
parent 81ca7445e9
commit 3c93e210ff
2 changed files with 62 additions and 118 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: msdosfs_conv.c,v 1.9 2013/01/26 16:51:51 christos Exp $ */
/* $NetBSD: msdosfs_conv.c,v 1.10 2014/09/01 09:09:47 martin Exp $ */
/*-
* Copyright (C) 1995, 1997 Wolfgang Solfrank.
@ -52,7 +52,7 @@
#endif
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: msdosfs_conv.c,v 1.9 2013/01/26 16:51:51 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: msdosfs_conv.c,v 1.10 2014/09/01 09:09:47 martin Exp $");
/*
* System include files.
@ -66,9 +66,11 @@ __KERNEL_RCSID(0, "$NetBSD: msdosfs_conv.c,v 1.9 2013/01/26 16:51:51 christos Ex
#include <sys/vnode.h>
#else
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <sys/queue.h>
#endif
#include <dev/clock_subr.h>
/*
* MSDOSFS include files.
@ -77,29 +79,15 @@ __KERNEL_RCSID(0, "$NetBSD: msdosfs_conv.c,v 1.9 2013/01/26 16:51:51 christos Ex
#include <fs/msdosfs/denode.h>
/*
* Days in each month in a regular year.
* The number of seconds between Jan 1, 1970 and Jan 1, 1980. In that
* interval there were 8 regular years and 2 leap years.
*/
u_short const regyear[] = {
31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31
};
#define DOSBIASYEAR 1980
#define SECONDSTO1980 (((8 * 365) + (2 * 366)) * (24 * 60 * 60))
/*
* Days in each month in a leap year.
* msdos fs can not store dates beyound the year 2234
*/
u_short const leapyear[] = {
31, 29, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31
};
/*
* Variables used to remember parts of the last time conversion. Maybe we
* can avoid a full conversion.
*/
u_long lasttime;
u_long lastday;
u_short lastddate;
u_short lastdtime;
#define DOSMAXYEAR ((DD_YEAR_MASK >> DD_YEAR_SHIFT) + DOSBIASYEAR)
/*
* Convert the unix version of time to dos's idea of time to be used in
@ -109,73 +97,50 @@ void
unix2dostime(const struct timespec *tsp, int gmtoff, u_int16_t *ddp, u_int16_t *dtp, u_int8_t *dhp)
{
u_long t;
u_long days;
u_long inc;
u_long year;
u_long month;
const u_short *months;
struct clock_ymdhms ymd;
t = tsp->tv_sec + gmtoff; /* time zone correction */
/*
* If the time from the last conversion is the same as now, then
* skip the computations and use the saved result.
* DOS timestamps can not represent dates before 1980.
*/
t = tsp->tv_sec + gmtoff; /* time zone correction */
t &= ~1;
if (lasttime != t) {
lasttime = t;
lastdtime = (((t / 2) % 30) << DT_2SECONDS_SHIFT)
+ (((t / 60) % 60) << DT_MINUTES_SHIFT)
+ (((t / 3600) % 24) << DT_HOURS_SHIFT);
if (t < SECONDSTO1980)
goto invalid_dos_date;
/*
* If the number of days since 1970 is the same as the last
* time we did the computation then skip all this leap year
* and month stuff.
*/
days = t / (24 * 60 * 60);
if (days != lastday) {
lastday = days;
for (year = 1970;; year++) {
inc = year & 0x03 ? 365 : 366;
if (days < inc)
break;
days -= inc;
}
months = year & 0x03 ? regyear : leapyear;
for (month = 0; month < 12; month++) {
if (days < months[month])
break;
days -= months[month];
}
lastddate = ((days + 1) << DD_DAY_SHIFT)
+ ((month + 1) << DD_MONTH_SHIFT);
/*
* Remember dos's idea of time is relative to 1980.
* unix's is relative to 1970. If somehow we get a
* time before 1980 then don't give totally crazy
* results.
*/
if (year > 1980)
lastddate += (year - 1980) << DD_YEAR_SHIFT;
}
}
if (dtp)
*dtp = lastdtime;
/*
* DOS granularity is 2 seconds
*/
t &= ~1;
/*
* Convert to year/month/day/.. format
*/
clock_secs_to_ymdhms(t, &ymd);
if (ymd.dt_year > DOSMAXYEAR)
goto invalid_dos_date;
/*
* Now transform to DOS format
*/
*ddp = (ymd.dt_day << DD_DAY_SHIFT)
+ (ymd.dt_mon << DD_MONTH_SHIFT)
+ ((ymd.dt_year - DOSBIASYEAR) << DD_YEAR_SHIFT);
if (dhp)
*dhp = (tsp->tv_sec & 1) * 100 + tsp->tv_nsec / 10000000;
if (dtp)
*dtp = (((t / 2) % 30) << DT_2SECONDS_SHIFT)
+ (((t / 60) % 60) << DT_MINUTES_SHIFT)
+ (((t / 3600) % 24) << DT_HOURS_SHIFT);
return;
*ddp = lastddate;
invalid_dos_date:
*ddp = 0;
if (dtp)
*dtp = 0;
if (dhp)
*dhp = 0;
}
/*
* The number of seconds between Jan 1, 1970 and Jan 1, 1980. In that
* interval there were 8 regular years and 2 leap years.
*/
#define SECONDSTO1980 (((8 * 365) + (2 * 366)) * (24 * 60 * 60))
u_short lastdosdate;
u_long lastseconds;
/*
* Convert from dos' idea of time to unix'. This will probably only be
* called from the stat(), and fstat() system calls and so probably need
@ -184,11 +149,8 @@ u_long lastseconds;
void
dos2unixtime(u_int dd, u_int dt, u_int dh, int gmtoff, struct timespec *tsp)
{
u_long seconds;
u_long m, month;
u_long y, year;
u_long days;
const u_short *months;
time_t seconds;
struct clock_ymdhms ymd;
if (dd == 0) {
/*
@ -198,37 +160,18 @@ dos2unixtime(u_int dd, u_int dt, u_int dh, int gmtoff, struct timespec *tsp)
tsp->tv_nsec = 0;
return;
}
seconds = ((dt & DT_2SECONDS_MASK) >> DT_2SECONDS_SHIFT) * 2
+ ((dt & DT_MINUTES_MASK) >> DT_MINUTES_SHIFT) * 60
+ ((dt & DT_HOURS_MASK) >> DT_HOURS_SHIFT) * 3600
+ dh / 100;
/*
* If the year, month, and day from the last conversion are the
* same then use the saved value.
*/
if (lastdosdate != dd) {
lastdosdate = dd;
days = 0;
year = (dd & DD_YEAR_MASK) >> DD_YEAR_SHIFT;
for (y = 0; y < year; y++)
days += y & 0x03 ? 365 : 366;
months = year & 0x03 ? regyear : leapyear;
/*
* Prevent going from 0 to 0xffffffff in the following
* loop.
*/
month = (dd & DD_MONTH_MASK) >> DD_MONTH_SHIFT;
if (month == 0) {
printf("%s: month value out of range (%ld)\n",
__func__, month);
month = 1;
}
for (m = 0; m < month - 1; m++)
days += months[m];
days += ((dd & DD_DAY_MASK) >> DD_DAY_SHIFT) - 1;
lastseconds = (days * 24 * 60 * 60) + SECONDSTO1980;
}
tsp->tv_sec = seconds + lastseconds;
memset(&ymd, 0, sizeof(ymd));
ymd.dt_year = ((dd & DD_YEAR_MASK) >> DD_YEAR_SHIFT) + 1980 ;
ymd.dt_mon = ((dd & DD_MONTH_MASK) >> DD_MONTH_SHIFT);
ymd.dt_day = ((dd & DD_DAY_MASK) >> DD_DAY_SHIFT);
ymd.dt_hour = (dt & DT_HOURS_MASK) >> DT_HOURS_SHIFT;
ymd.dt_min = (dt & DT_MINUTES_MASK) >> DT_MINUTES_SHIFT;
ymd.dt_sec = ((dt & DT_2SECONDS_MASK) >> DT_2SECONDS_SHIFT) * 2;
seconds = clock_ymdhms_to_secs(&ymd);
tsp->tv_sec = seconds;
tsp->tv_sec -= gmtoff; /* time zone correction */
tsp->tv_nsec = (dh % 100) * 10000000;
}

View File

@ -1,10 +1,10 @@
# $NetBSD: Makefile.inc,v 1.5 2013/01/26 16:50:46 christos Exp $
# $NetBSD: Makefile.inc,v 1.6 2014/09/01 09:09:47 martin Exp $
#
MSDOS= ${NETBSDSRCDIR}/sys/fs/msdosfs
MSDOS_NEWFS= ${NETBSDSRCDIR}/sbin/newfs_msdos
.PATH: ${.CURDIR}/msdos ${MSDOS} ${MSDOS_NEWFS}
.PATH: ${.CURDIR}/msdos ${MSDOS} ${MSDOS_NEWFS} ${NETBSDSRCDIR}/sys/dev
CPPFLAGS+= -DMSDOS_EI -I${MSDOS} -I${MSDOS_NEWFS}
.if !defined(HOSTPROGNAME)
@ -13,3 +13,4 @@ CPPFLAGS+= -I${NETBSDSRCDIR}/sys
SRCS+= mkfs_msdos.c msdosfs_fat.c msdosfs_conv.c msdosfs_vfsops.c
SRCS+= msdosfs_lookup.c msdosfs_denode.c msdosfs_vnops.c
SRCS+= clock_subr.c