When creating a new archive entry, have zipfile store UTC instead of local

time in the legacy MS-DOS format timestamp field.

FossilOrigin-Name: e2114df18383d111dd5fbac902e08b42a7f4b2b2d6f7bf29574a3722e4a4dad5
This commit is contained in:
dan 2018-01-31 19:13:31 +00:00
parent 5cd253423b
commit 44091ed368
5 changed files with 145 additions and 56 deletions

View File

@ -686,18 +686,34 @@ static int zipfileScanExtra(u8 *aExtra, int nExtra, u32 *pmTime){
**
** https://msdn.microsoft.com/en-us/library/9kkf9tah.aspx
*/
static time_t zipfileMtime(ZipfileCDS *pCDS){
struct tm t;
memset(&t, 0, sizeof(t));
t.tm_sec = (pCDS->mTime & 0x1F)*2;
t.tm_min = (pCDS->mTime >> 5) & 0x2F;
t.tm_hour = (pCDS->mTime >> 11) & 0x1F;
static u32 zipfileMtime(ZipfileCDS *pCDS){
int Y = (1980 + ((pCDS->mDate >> 9) & 0x7F));
int M = ((pCDS->mDate >> 5) & 0x0F);
int D = (pCDS->mDate & 0x1F);
int B = -13;
t.tm_mday = (pCDS->mDate & 0x1F);
t.tm_mon = ((pCDS->mDate >> 5) & 0x0F) - 1;
t.tm_year = 80 + ((pCDS->mDate >> 9) & 0x7F);
int sec = (pCDS->mTime & 0x1F)*2;
int min = (pCDS->mTime >> 5) & 0x3F;
int hr = (pCDS->mTime >> 11) & 0x1F;
return mktime(&t);
/* JD = INT(365.25 * (Y+4716)) + INT(30.6001 * (M+1)) + D + B - 1524.5 */
/* Calculate the JD in seconds for noon on the day in question */
if( M<3 ){
Y = Y-1;
M = M+12;
}
i64 JD = (i64)(24*60*60) * (
(int)(365.25 * (Y + 4716))
+ (int)(30.6001 * (M + 1))
+ D + B - 1524
);
/* Correct the JD for the time within the day */
JD += (hr-12) * 3600 + min * 60 + sec;
/* Convert JD to unix timestamp (the JD epoch is 2440587.5) */
return (u32)(JD - (i64)(24405875) * 24*60*6);
}
/*
@ -706,24 +722,36 @@ static time_t zipfileMtime(ZipfileCDS *pCDS){
** to the UNIX timestamp value passed as the second.
*/
static void zipfileMtimeToDos(ZipfileCDS *pCds, u32 mUnixTime){
time_t t = (time_t)mUnixTime;
struct tm res;
/* Convert unix timestamp to JD (2440588 is noon on 1/1/1970) */
i64 JD = (i64)2440588 + mUnixTime / (24*60*60);
#if !defined(_WIN32) && !defined(WIN32)
localtime_r(&t, &res);
#else
memcpy(&res, localtime(&t), sizeof(struct tm));
#endif
int A, B, C, D, E;
int yr, mon, day;
int hr, min, sec;
pCds->mTime = (u16)(
(res.tm_sec / 2) +
(res.tm_min << 5) +
(res.tm_hour << 11));
A = (int)((JD - 1867216.25)/36524.25);
A = JD + 1 + A - (A/4);
B = A + 1524;
C = (int)((B - 122.1)/365.25);
D = (36525*(C&32767))/100;
E = (int)((B-D)/30.6001);
pCds->mDate = (u16)(
(res.tm_mday-1) +
((res.tm_mon+1) << 5) +
((res.tm_year-80) << 9));
day = B - D - (int)(30.6001*E);
mon = (E<14 ? E-1 : E-13);
yr = mon>2 ? C-4716 : C-4715;
hr = (mUnixTime % (24*60*60)) / (60*60);
min = (mUnixTime % (60*60)) / 60;
sec = (mUnixTime % 60);
pCds->mDate = (u16)(day + (mon << 5) + ((yr-1980) << 9));
pCds->mTime = (u16)(sec/2 + (min<<5) + (hr<<11));
assert( mUnixTime<315507600
|| mUnixTime==zipfileMtime(pCds)
|| ((mUnixTime % 2) && mUnixTime-1==zipfileMtime(pCds))
/* || (mUnixTime % 2) */
);
}
/*

View File

@ -1,5 +1,5 @@
C Improve\sthe\somit-left-join\soptimization\sso\sthat\sit\sworks\sin\ssome\scases\s\nwhen\sthe\sRHS\sis\ssubject\sto\sa\sUNIQUE\sbut\snot\sNOT\sNULL\sconstraint.
D 2018-01-31T16:50:27.186
C When\screating\sa\snew\sarchive\sentry,\shave\szipfile\sstore\sUTC\sinstead\sof\slocal\ntime\sin\sthe\slegacy\sMS-DOS\sformat\stimestamp\sfield.
D 2018-01-31T19:13:31.142
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F Makefile.in 7a3f714b4fcf793108042b7b0a5c720b0b310ec84314d61ba7f3f49f27e550ea
@ -304,7 +304,7 @@ F ext/misc/vfsstat.c bf10ef0bc51e1ad6756629e1edb142f7a8db1178
F ext/misc/vtablog.c 31d0d8f4406795679dcd3a67917c213d3a2a5fb3ea5de35f6e773491ed7e13c9
F ext/misc/vtshim.c 1976e6dd68dd0d64508c91a6dfab8e75f8aaf6cd
F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212
F ext/misc/zipfile.c aa10ec6a235030cd368b511e7c78e40251008dddddeb0eb006ad1f344f78b690
F ext/misc/zipfile.c 56028f7e74d948b7bef834624d128f563eb63f5950248d538afa9d0f6c3365dc
F ext/rbu/rbu.c ea7d1b7eb44c123a2a619332e19fe5313500705c4a58aaa1887905c0d83ffc2e
F ext/rbu/rbu1.test 43836fac8c7179a358eaf38a8a1ef3d6e6285842
F ext/rbu/rbu10.test 1846519a438697f45e9dcb246908af81b551c29e1078d0304fae83f1fed7e9ee
@ -1603,8 +1603,8 @@ F test/wordcount.c cb589cec469a1d90add05b1f8cee75c7210338d87a5afd65260ed5c0f4bbf
F test/writecrash.test f1da7f7adfe8d7f09ea79b42e5ca6dcc41102f27f8e334ad71539501ddd910cc
F test/zeroblob.test 3857870fe681b8185654414a9bccfde80b62a0fa
F test/zerodamage.test 9c41628db7e8d9e8a0181e59ea5f189df311a9f6ce99cc376dc461f66db6f8dc
F test/zipfile.test 368a5a0c97be0caaf8c3efa8293bfe18436d546805678fa00b6aa81bc98727ec
F test/zipfile2.test 1066dd9769028d6f0bf1c87303b24f087cc064d9bbcacefc95613380f642de18
F test/zipfile.test 3695ab6d731720ca0b542fe21ded39d4a34891f4a590b2e6c909c9ff07e13148
F test/zipfile2.test 5f93611307c131e83f226a471231d769b794b9e8c6a675cfa3d34b1a79df23fe
F test/zipfilefault.test df4fa9e16116e0cb21d09037a6b0a7d93fecd8767d82154b66044b4ca43fca58
F tool/GetFile.cs a15e08acb5dd7539b75ba23501581d7c2b462cb5
F tool/GetTclKit.bat 8995df40c4209808b31f24de0b58f90930239a234f7591e3675d45bfbb990c5d
@ -1704,8 +1704,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 32ed9c106710c74a12d60ec33027fd6a9335627c95642ba608593b2735714da6 74d857d178dfadea7e07ba47439fe11aa9d282b54caf78cd6961e593b37406d0
R ee3ce7babbd6fba601d683cb41b035ba
T +closed 74d857d178dfadea7e07ba47439fe11aa9d282b54caf78cd6961e593b37406d0
U drh
Z 20db364b7139e3a10e7c112d48b03b80
P 02ba8a7ba7ba71cd7abd5dd3093ea486f53a025f6972bb444f2da37e0e2fc3b2
R 4025431a2ff076723fc2f621d10c0c47
T *branch * zipfile-timestamp-fix
T *sym-zipfile-timestamp-fix *
T -sym-trunk *
U dan
Z 7679dfe9f8ef39802f520b9ec5eb4496

View File

@ -1 +1 @@
02ba8a7ba7ba71cd7abd5dd3093ea486f53a025f6972bb444f2da37e0e2fc3b2
e2114df18383d111dd5fbac902e08b42a7f4b2b2d6f7bf29574a3722e4a4dad5

View File

@ -48,6 +48,18 @@ if {$::tcl_platform(platform)=="unix" && [catch {exec unzip}]==0} {
}
}
# The argument is a blob (not a hex string) containing a zip archive.
# This proc removes the extended timestamp fields from the archive
# and returns the result.
#
proc remove_timestamps {blob} {
set hex [binary encode hex $blob]
set hex [string map {55540500 00000500} $hex]
binary decode hex $hex
}
# Argument $file is the name of a zip archive on disk. This function
# executes test cases to check that the results of each of the following
# are the same:
@ -367,6 +379,48 @@ do_catchsql_test 4.2 {
CREATE VIRTUAL TABLE yyy USING zipfile('test.zip', 'test.zip');
} {1 {zipfile constructor requires one argument}}
#--------------------------------------------------------------------------
db func rt remove_timestamps
do_execsql_test 5.0 {
WITH c(name,mtime,data) AS (
SELECT 'a.txt', 946684800, 'abc'
)
SELECT name,mtime,data FROM zipfile(
( SELECT rt( zipfile(name,NULL,mtime,data) ) FROM c )
)
} {
a.txt 946684800 abc
}
if {[info vars ::UNZIP]!=""} {
load_static_extension db fileio
forcedelete test.zip
do_test 6.0 {
execsql {
WITH c(name,mtime,data) AS (
SELECT 'a.txt', 946684800, 'abc' UNION ALL
SELECT 'b.txt', 1000000000, 'abc' UNION ALL
SELECT 'c.txt', 1111111000, 'abc'
)
SELECT writefile('test.zip',
( SELECT rt ( zipfile(name,NULL,mtime,data) ) FROM c )
);
}
forcedelete test_unzip
file mkdir test_unzip
exec unzip -d test_unzip test.zip
db eval {
SELECT name, mtime FROM fsdir('test_unzip') WHERE name!='test_unzip'
ORDER BY name
}
} [list {*}{
test_unzip/a.txt 946684800
test_unzip/b.txt 1000000000
test_unzip/c.txt 1111111000
}]
}
finish_test

View File

@ -70,12 +70,17 @@ set archive {
00007A0000000000
}
do_execsql_test 3.1 {
WITH contents(name,mtime,data) AS (
VALUES('a.txt', 1000000, 'contents of a.txt') UNION ALL
VALUES('b.txt', 1000000, 'contents of b.txt')
) SELECT quote( zipfile(name,NULL,mtime,data) ) FROM contents;
} [blobliteral $archive]
if 0 {
# This test is broken - the archive generated is slightly different
# depending on the zlib version used.
do_execsql_test 3.1 {
WITH contents(name,mtime,data) AS (
VALUES('a.txt', 1000000, 'contents of a.txt') UNION ALL
VALUES('b.txt', 1000000, 'contents of b.txt')
) SELECT quote( zipfile(name,NULL,mtime,data) ) FROM contents;
} [blobliteral $archive]
}
set blob [blob $archive]
do_execsql_test 3.2 {
@ -98,6 +103,7 @@ for {set i 0} {$i < [llength $L]} {incr i} {
} {/1 .*/}
}
# Change the "extra info id" for all extended-timestamp fields.
set L [findall 5554 $archive]
for {set i 0} {$i < [llength $L]} {incr i} {
set idx [lindex $L $i]
@ -123,20 +129,18 @@ for {set i 0} {$i < [llength $L]} {incr i} {
}
}
if 0 {
set blob [db one {
WITH contents(name,mtime,data) AS (
VALUES('a.txt', 1000000, 'aaaaaaaaaaaaaaaaaaaaaaa')
) SELECT quote( zipfile(name,NULL,mtime,data) ) FROM contents;
}]
set blob [string range $blob 2 end]
set blob [string range $blob 0 end-1]
while {[string length $blob]>0} {
puts [string range $blob 0 63]
set blob [string range $blob 64 end]
}
exit
}
# set blob [db one {
# WITH contents(name,mtime,data) AS (
# VALUES('a.txt', 1000000, 'aaaaaaaaaaaaaaaaaaaaaaa')
# ) SELECT quote( zipfile(name,NULL,mtime,data) ) FROM contents;
# }]
# set blob [string range $blob 2 end]
# set blob [string range $blob 0 end-1]
# while {[string length $blob]>0} {
# puts [string range $blob 0 63]
# set blob [string range $blob 64 end]
# }
# exit
set archive2 {
504B0304140000080800D4A52BEC08F54C6E050000001700000005000900612E
@ -161,5 +165,6 @@ do_catchsql_test 4.1 {
} {1 {inflate() failed (0)}}
finish_test