-
Notifications
You must be signed in to change notification settings - Fork 0
/
fix-onedrive-zip
executable file
·155 lines (115 loc) · 3.83 KB
/
fix-onedrive-zip
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#!/usr/bin/perl
# fix-onedrive-zip
#
# Fix OneDrive/Windows Zip files larger than 4Gig that have an invalid
# 'Total Number of Disks' field in the 'ZIP64 End Central Directory
# Locator'. The value in this field should be 1, but OneDrive/Windows sets
# it to 0. This makes it difficult to work with these files using standard
# unzip utilities.
#
# This program changes the 'Total Number of Disks' field value to 1.
#
# Copyright (c) 2020 Paul Marquess. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the same terms as Perl itself.
use strict;
use warnings;
use Fcntl qw(SEEK_SET SEEK_END);
use Getopt::Long;
# Signatures for the headers we need to check
use constant ZIP_LOCAL_HDR_SIG => 0x04034b50;
use constant ZIP_END_CENTRAL_HDR_SIG => 0x06054b50;
use constant ZIP64_END_CENTRAL_LOC_HDR_SIG => 0x07064b50;
sub Seek;
sub Read;
my $VERSION = '1.00' ;
my $dry_run ;
GetOptions ("dry-run" => \$dry_run,
"help" => \&Usage)
or Usage("Error in command line arguments\n");
Usage()
unless @ARGV >= 1;
for my $filename (@ARGV)
{
open my $fh, "+<$filename"
or die "Error: Cannot open '$filename': $!\n";
}
for my $filename (@ARGV)
{
print "\nChecking '$filename'\n";
open my $fh, "+<$filename"
or die "Cannot open '$filename': $!\n";
my $data = Read $filename, $fh, 4;
my $sig = unpack("V", $data) ;
die "Error: No Zip signature at start of '$filename'\n"
unless $sig == ZIP_LOCAL_HDR_SIG ;
# Assume no comment or other trailing data
# The last two things n the file are the Z64 & EOCD records
Seek $filename, $fh, -42 ;
$data = Read $filename, $fh, 42;
my $eocd = substr($data, 20);
my $eocd_sig = unpack("V", substr($eocd, 0, 4)) ;
die "Error: Cannot find Zip signature at end of '$filename'\n"
unless $eocd_sig == ZIP_END_CENTRAL_HDR_SIG ;
my $offset = unpack("VV", substr($eocd, 16, 4)) ;
die sprintf "Error: bad offset 0x%X at end of '$filename'\n", $offset
unless $offset == 0xFFFFFFFF ;
my $z64_sig = unpack("V", substr($data, 0, 4)) ;
die "Error: Cannot find Zip64 signature at end of '$filename'\n"
unless $z64_sig == ZIP64_END_CENTRAL_LOC_HDR_SIG ;
my $total_disks = unpack("V", substr($data, 16, 4)) ;
if ($total_disks == 1)
{
print "Nothing to do: 'Total Number of Disks' field is already 1\n";
next
}
if ($total_disks != 0)
{
die "Error: 'Total Number of Disks' field is $total_disks\n";
}
Seek $filename, $fh, -42 + 16 ;
if ($dry_run)
{
print "Dry-Run: No change made to '$filename'\n";
}
else
{
print $fh pack "V", 1 ;
print "Updated '$filename'\n";
}
}
sub Seek
{
my $filename = shift;
my $fh = shift ;
my $offset = shift ;
seek $fh, $offset, SEEK_END
or die "Cannot seek '$filename': $!\n" ;
}
sub Read
{
my $filename = shift ;
my $fh = shift;
my $size = shift ;
my $data ;
read($fh, $data, $size) == $size
or die "Cannot read from '$filename': $!\n" ;
return $data;
}
sub Usage
{
print <<'EOM';
Usage: fix-onedrive-zip [--dry-run] file1.zip [file2.zip...]
Fix OneDrive/Windows Zip files larger than 4Gig that have an invalid 'Total
Number of Disks' field in the 'ZIP64 End Central Directory Locator'. The
value in this field should be 1, but OneDrive/Windows sets it to 0. This
makes it difficult to work with these files using standard unzip utilities.
This program changes the 'Total Number of Disks' field value to 1.
See https://github.com/pmqs/Fix-OneDrive-Zip for support.
Copyright (c) 2020 Paul Marquess (pmqs@cpan.org). All rights reserved.
This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
EOM
exit;
}