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:
parent
5cd253423b
commit
44091ed368
@ -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) */
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
|
22
manifest
22
manifest
@ -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
|
||||
|
@ -1 +1 @@
|
||||
02ba8a7ba7ba71cd7abd5dd3093ea486f53a025f6972bb444f2da37e0e2fc3b2
|
||||
e2114df18383d111dd5fbac902e08b42a7f4b2b2d6f7bf29574a3722e4a4dad5
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user