2000-11-24 14:19:29

by Igor Yu. Zhbanov

[permalink] [raw]
Subject: Bug in date converting functions DOS<=>UNIX in FAT, NCPFS and SMBFS drivers

diff -ur linux-2.2.17/fs/fat/misc.c linux/fs/fat/misc.c
--- linux-2.2.17/fs/fat/misc.c Thu May 4 04:16:46 2000
+++ linux/fs/fat/misc.c Wed Nov 22 14:05:08 2000
@@ -2,6 +2,8 @@
* linux/fs/fat/misc.c
*
* Written 1992,1993 by Werner Almesberger
+ * 22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980
+ * and date_dos2unix for date==0 by Igor Zhbanov([email protected])
*/

#include <linux/fs.h>
@@ -288,7 +290,9 @@
{
int month,year,secs;

- month = ((date >> 5) & 15)-1;
+ /* first subtract and mask after that... Otherwise, if
+ date == 0, bad things happen */
+ month = ((date >> 5) - 1) & 15;
year = date >> 9;
secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
@@ -310,6 +314,8 @@
unix_date -= sys_tz.tz_minuteswest*60;
if (sys_tz.tz_dsttime) unix_date += 3600;

+ if (unix_date < 315532800)
+ unix_date = 315532800; /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */
*time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
(((unix_date/3600) % 24) << 11);
day = unix_date/86400-3652;
diff -ur linux-2.2.17/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c
--- linux-2.2.17/fs/ncpfs/dir.c Thu Jun 8 01:26:43 2000
+++ linux/fs/ncpfs/dir.c Wed Nov 22 14:06:09 2000
@@ -5,6 +5,8 @@
* Modified for big endian by J.F. Chadima and David S. Miller
* Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
* Modified 1998 Wolfram Pienkoss for NLS
+ * 22/11/2000 - Fixed ncp_date_unix2dos for dates earlier than 01/01/1980
+ * by Igor Zhbanov([email protected])
*
*/

@@ -1158,6 +1160,8 @@
int day, year, nl_day, month;

unix_date = utc2local(unix_date);
+ if (unix_date < 315532800)
+ unix_date = 315532800; /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */
*time = (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) +
(((unix_date / 3600) % 24) << 11);
day = unix_date / 86400 - 3652;
diff -ur linux-2.2.17/fs/smbfs/ChangeLog linux/fs/smbfs/ChangeLog
--- linux-2.2.17/fs/smbfs/ChangeLog Mon Sep 4 21:39:27 2000
+++ linux/fs/smbfs/ChangeLog Wed Nov 22 14:10:40 2000
@@ -1,5 +1,10 @@
ChangeLog for smbfs.

+2000-11-22 Igor Zhbanov <[email protected]>
+
+ * proc.c: fixed date_unix2dos for dates earlier than 01/01/1980
+ and date_dos2unix for date==0
+
2000-07-20 Urban Widmark <[email protected]>

* proc.c: fix 2 places where bad server responses could cause an Oops.
diff -ur linux-2.2.17/fs/smbfs/proc.c linux/fs/smbfs/proc.c
--- linux-2.2.17/fs/smbfs/proc.c Mon Sep 4 21:39:27 2000
+++ linux/fs/smbfs/proc.c Wed Nov 22 14:13:32 2000
@@ -169,7 +169,9 @@
int month, year;
time_t secs;

- month = ((date >> 5) & 15) - 1;
+ /* first subtract and mask after that... Otherwise, if
+ date == 0, bad things happen */
+ month = ((date >> 5) - 1) & 15;
year = date >> 9;
secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 + 86400 *
((date & 31) - 1 + day_n[month] + (year / 4) + year * 365 - ((year & 3) == 0 &&
@@ -188,6 +190,8 @@
int day, year, nl_day, month;

unix_date = utc2local(server, unix_date);
+ if (unix_date < 315532800)
+ unix_date = 315532800; /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */
*time = (unix_date % 60) / 2 +
(((unix_date / 60) % 60) << 5) +
(((unix_date / 3600) % 24) << 11);


2000-11-28 18:56:47

by Urban Widmark

[permalink] [raw]
Subject: Re: Bug in date converting functions DOS<=>UNIX in FAT, NCPFS and SMBFS drivers

On Fri, 24 Nov 2000, Igor Yu. Zhbanov wrote:

> Hello!

Hello, sorry for the slow response.

> I have found a bug in drivers of file systems which use a DOS-like format
> of date (16 bit: years since 1980 - 7 bits, month - 4 bits, day - 5 bits).

[snip]

> 2) VFAT for example have three kinds of dates: creation date, modification date
> and access date. Sometimes one of these dates is set to zero (which indicates
> that this date is not set). Zero is not a valid date (e.g. months are
> numbered from one, not from zero) and can't be properly converted to
> UNIX-like format of date (it was converted to date before 1980).

Days are also numbered from one (at least smbfs) and this change doesn't
do anything about that. An all zero date gives 315446400 (or else my
testprogram is broken) and you wanted it to give 315532800 (?). So that
should be fixed too, I think.

It would be nice if someone would rewrite these shift-and-mask orgies into
something with a bit more structure (bitfields? hmm, endianess problems?
undefined compiler behaviour? I don't know ... macros?).

I'm having trouble following these, but maybe that's just me.

/Urban