-
Notifications
You must be signed in to change notification settings - Fork 24
/
fix-onedrive-zip
executable file
·172 lines (129 loc) · 4.28 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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#!/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-2024 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.02' ;
my $dry_run ;
BEGIN {
# Check for a 32-bit Perl
if (!eval { pack "Q", 1 }) {
warn "The perl executable you are running is 32-bit.\n" .
"You need to install a 64-bit perl executable to continue\n";
exit(1);
}
}
GetOptions ("dry-run" => \$dry_run,
"help" => \&Usage)
or Usage("Error in command line arguments\n");
Usage()
unless @ARGV >= 1;
# run a quick sanility test on all the zip files
for my $filename (@ARGV)
{
# check exists & can read
open my $fh, "+<$filename"
or die "Error: Cannot open '$filename': $!\n";
# check no empty &
my $fileSize = -s $filename ;
die "Error: zip file '$filename' is empty\n"
if $fileSize == 0;
}
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 in 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-2024 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;
}