├── test ├── data.txt ├── zero.zip ├── mkbad └── fix.t ├── assets ├── select.png └── download.png ├── .github ├── dependabot.yml └── workflows │ ├── linux.yml │ ├── macos.yml │ └── windows.yml ├── .cirrus.yml ├── fix-onedrive-zip └── README.md /test/data.txt: -------------------------------------------------------------------------------- 1 | this is a test 2 | -------------------------------------------------------------------------------- /test/zero.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmqs/Fix-OneDrive-Zip/HEAD/test/zero.zip -------------------------------------------------------------------------------- /assets/select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmqs/Fix-OneDrive-Zip/HEAD/assets/select.png -------------------------------------------------------------------------------- /assets/download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmqs/Fix-OneDrive-Zip/HEAD/assets/download.png -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "monthly" 7 | target-branch: "master" -------------------------------------------------------------------------------- /.cirrus.yml: -------------------------------------------------------------------------------- 1 | task: 2 | name: FreeBSD 3 | freebsd_instance: 4 | matrix: 5 | # image: freebsd-11-4-release-amd64 6 | # image: freebsd-12-2-release-amd64 7 | image: freebsd-13-2-release-amd64 8 | # image: freebsd-14-0-release-amd64 9 | install_script: 10 | - pkg info 11 | - pkg install -y perl5 12 | # unzip_script: 13 | # - unzip --version 14 | build_script: 15 | - perl -V 16 | test_script: 17 | - perl -c fix-onedrive-zip 18 | - prove -v test 19 | 20 | 21 | # task: 22 | # name: ARM 23 | # arm_container: 24 | # image: ubuntu:latest 25 | # cpu: 4 26 | # memory: 12G 27 | # build_script: 28 | # - perl -V 29 | # test_script: 30 | # - perl -c fix-onedrive-zip 31 | # - prove -v test -------------------------------------------------------------------------------- /.github/workflows/linux.yml: -------------------------------------------------------------------------------- 1 | name: Linux build 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | pull_request: 7 | 8 | jobs: 9 | build: 10 | 11 | runs-on: ubuntu-latest 12 | 13 | strategy: 14 | matrix: 15 | perl: 16 | - '5.42' 17 | - '5.40' 18 | - '5.38' 19 | - '5.36' 20 | - '5.34' 21 | - '5.32' 22 | - '5.30' 23 | - '5.28' 24 | - '5.26' 25 | - '5.24' 26 | - '5.22' 27 | - '5.20' 28 | - '5.18' 29 | - '5.16' 30 | - '5.14' 31 | - '5.12' 32 | - '5.10' 33 | - '5.8' 34 | 35 | name: Perl ${{ matrix.perl }} 36 | steps: 37 | - uses: actions/checkout@v6 38 | - name: Setup perl 39 | uses: shogo82148/actions-setup-perl@v1 40 | with: 41 | perl-version: ${{ matrix.perl }} 42 | - name: Perl version 43 | run: perl -V 44 | - name: Unzip version 45 | run: unzip -h 46 | - name: Syntax Check 47 | run: perl -c fix-onedrive-zip 48 | - name: Test 49 | run: prove -v test 50 | -------------------------------------------------------------------------------- /.github/workflows/macos.yml: -------------------------------------------------------------------------------- 1 | name: Macos build 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | pull_request: 7 | 8 | jobs: 9 | build: 10 | 11 | runs-on: macos-latest 12 | 13 | strategy: 14 | matrix: 15 | perl: 16 | - '5.42' 17 | - '5.40' 18 | - '5.38' 19 | - '5.36' 20 | - '5.34' 21 | - '5.32' 22 | - '5.30' 23 | - '5.28' 24 | - '5.26' 25 | - '5.24' 26 | - '5.22' 27 | - '5.20' 28 | - '5.18' 29 | - '5.16' 30 | - '5.14' 31 | - '5.12' 32 | - '5.10' 33 | - '5.8' 34 | 35 | name: Perl ${{ matrix.perl }} 36 | steps: 37 | - uses: actions/checkout@v6 38 | - name: Setup perl 39 | uses: shogo82148/actions-setup-perl@v1 40 | with: 41 | perl-version: ${{ matrix.perl }} 42 | - name: Perl version 43 | run: perl -V 44 | - name: Unzip version 45 | run: unzip -h 46 | - name: Syntax Check 47 | run: perl -c fix-onedrive-zip 48 | - name: Test 49 | run: prove -v test 50 | -------------------------------------------------------------------------------- /.github/workflows/windows.yml: -------------------------------------------------------------------------------- 1 | name: Windows build 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | pull_request: 7 | 8 | jobs: 9 | build: 10 | 11 | runs-on: windows-latest 12 | 13 | strategy: 14 | matrix: 15 | perl: 16 | - '5.42' 17 | - '5.40' 18 | - '5.38' 19 | - '5.36' 20 | - '5.34' 21 | - '5.32' 22 | - '5.30' 23 | - '5.28' 24 | - '5.26' 25 | - '5.24' 26 | - '5.22' 27 | - '5.20' 28 | - '5.18' 29 | - '5.16' 30 | - '5.14' 31 | # - '5.12' 32 | # - '5.10' 33 | # - '5.8' 34 | 35 | name: Perl ${{ matrix.perl }} 36 | steps: 37 | - uses: actions/checkout@v6 38 | - name: Setup perl 39 | uses: shogo82148/actions-setup-perl@v1 40 | with: 41 | perl-version: ${{ matrix.perl }} 42 | - name: Perl version 43 | run: perl -V 44 | - name: Unzip version 45 | run: unzip -h 46 | - name: Syntax Check 47 | run: perl -c fix-onedrive-zip 48 | - name: Test 49 | run: perl test\fix.t 50 | -------------------------------------------------------------------------------- /test/mkbad: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # mkbad 4 | # 5 | # This is a hacked version of the 'fix-onedrive-zip' script. 6 | # It is used for testing only. The script will take a well-formed zip file 7 | # and modify it to have the issue that fix-onedrive-zip 8 | # is used to address. 9 | # 10 | 11 | use strict; 12 | use warnings; 13 | 14 | use Fcntl qw(SEEK_SET SEEK_END); 15 | use Getopt::Long; 16 | 17 | # Signatures for the headers we need to check 18 | use constant ZIP_LOCAL_HDR_SIG => 0x04034b50; 19 | use constant ZIP_END_CENTRAL_HDR_SIG => 0x06054b50; 20 | use constant ZIP64_END_CENTRAL_LOC_HDR_SIG => 0x07064b50; 21 | 22 | sub Seek; 23 | sub Read; 24 | 25 | my $VERSION = '1.00' ; 26 | my $dry_run ; 27 | 28 | GetOptions ("dry-run" => \$dry_run) 29 | or Usage("Error in command line arguments\n"); 30 | 31 | Usage() 32 | unless @ARGV >= 1; 33 | 34 | for my $filename (@ARGV) 35 | { 36 | open my $fh, "+<$filename" 37 | or die "Error: Cannot open '$filename': $!\n"; 38 | } 39 | 40 | for my $filename (@ARGV) 41 | { 42 | print "\nChecking '$filename'\n"; 43 | open my $fh, "+<$filename" 44 | or die "Cannot open '$filename': $!\n"; 45 | 46 | my $data = Read $filename, $fh, 4; 47 | 48 | my $sig = unpack("V", $data) ; 49 | 50 | die "Error: No Zip signature at start of '$filename'\n" 51 | unless $sig == ZIP_LOCAL_HDR_SIG ; 52 | 53 | # Assume no comment or other trailing data 54 | # The last two things in the file are the Z64 & EOCD records 55 | 56 | Seek $filename, $fh, -42 ; 57 | 58 | $data = Read $filename, $fh, 42; 59 | 60 | my $eocd = substr($data, 20); 61 | my $eocd_sig = unpack("V", substr($eocd, 0, 4)) ; 62 | 63 | die "Error: Cannot find Zip signature at end of '$filename'\n" 64 | unless $eocd_sig == ZIP_END_CENTRAL_HDR_SIG ; 65 | 66 | my $offset = unpack("VV", substr($eocd, 16, 4)) ; 67 | 68 | die sprintf "Error: bad offset 0x%X at end of '$filename'\n", $offset 69 | unless $offset == 0xFFFFFFFF ; 70 | 71 | my $z64_sig = unpack("V", substr($data, 0, 4)) ; 72 | 73 | die "Error: Cannot find Zip64 signature at end of '$filename'\n" 74 | unless $z64_sig == ZIP64_END_CENTRAL_LOC_HDR_SIG ; 75 | 76 | my $total_disks = unpack("V", substr($data, 16, 4)) ; 77 | 78 | # if ($total_disks == 1) 79 | # { 80 | # print "Nothing to do: 'Total Number of Disks' field is already 1\n"; 81 | # next 82 | # } 83 | # 84 | # if ($total_disks != 0) 85 | # { 86 | # die "Error: 'Total Number of Disks' field is $total_disks\n"; 87 | # } 88 | 89 | Seek $filename, $fh, -42 + 16 ; 90 | 91 | if ($dry_run) 92 | { 93 | print "Dry-Run: No change made to '$filename'\n"; 94 | } 95 | else 96 | { 97 | # This line creates the bad zip file 98 | print $fh pack "V", 0 ; 99 | print "Updated '$filename'\n"; 100 | } 101 | } 102 | 103 | sub Seek 104 | { 105 | my $filename = shift; 106 | my $fh = shift ; 107 | my $offset = shift ; 108 | 109 | seek $fh, $offset, SEEK_END 110 | or die "Cannot seek '$filename': $!\n" ; 111 | } 112 | 113 | sub Read 114 | { 115 | my $filename = shift ; 116 | my $fh = shift; 117 | my $size = shift ; 118 | 119 | my $data ; 120 | 121 | read($fh, $data, $size) == $size 122 | or die "Cannot read from '$filename': $!\n" ; 123 | 124 | return $data; 125 | } 126 | -------------------------------------------------------------------------------- /test/fix.t: -------------------------------------------------------------------------------- 1 | 2 | use strict; 3 | use warnings; 4 | 5 | use File::Temp qw(tempdir); 6 | use Test::More tests => 17; 7 | use File::Copy; 8 | use Cwd; 9 | 10 | my $HERE = getcwd(); 11 | my $testDir = $HERE . '/test'; 12 | my $FixZip = $HERE . '/fix-onedrive-zip'; 13 | my $BadZIP = 'zero.zip'; 14 | 15 | my ($status, $stdout, $stderr) ; 16 | 17 | my $dir = tempdir(CLEANUP => 1); 18 | # my $dir = "/tmp/fix"; mkdir "/tmp/fix"; 19 | 20 | chdir $dir 21 | or die "Cannot chdir to '$dir': $!\n"; 22 | 23 | { 24 | # Error: zip file does not exist 25 | ################################ 26 | diag "Zip file does not exist"; 27 | my $not_there = "not-exist"; 28 | ($status, $stdout, $stderr) = run("perl $FixZip $not_there"); 29 | 30 | isnt $status, 0, "fix-onedrive-zip returned non-zero" ; 31 | is $stdout, "", "no stdout"; 32 | like $stderr, qr/Error: Cannot open '$not_there': No such file or directory/, "'$not_there' does not exist"; 33 | } 34 | 35 | { 36 | # Error: zip file is empty 37 | ########################## 38 | diag "Zip file is empty"; 39 | my $empty = "empty"; 40 | open my $fh, ">", $empty 41 | or die "Error: Cannot open '$empty': $!\n"; 42 | 43 | close $fh; 44 | 45 | is -s $empty, 0, "test file is empty"; 46 | 47 | ($status, $stdout, $stderr) = run("perl $FixZip $empty"); 48 | 49 | isnt $status, 0, "fix-onedrive-zip returned non-zero" ; 50 | is $stdout, "", "no stdout"; 51 | like $stderr, qr/Error: zip file '$empty' is empty/, "'$empty' is empty"; 52 | } 53 | 54 | { 55 | # Fix a zip file 56 | ################ 57 | 58 | copy($testDir . '/' . $BadZIP, $BadZIP) 59 | or die "Cannot copy $BadZIP to $dir: $!\n"; 60 | 61 | ($status, $stdout, $stderr) = run("perl $FixZip $BadZIP"); 62 | 63 | is $status, 0, "fix-onedrive-zip returned zero" ; 64 | 65 | # Now check that the zip file has been fixed 66 | ############################################# 67 | ($status, $stdout, $stderr) = run("unzip -l $BadZIP"); 68 | 69 | is $status, 0, "unzip -l returned zero for fixed zip file"; 70 | 71 | # Output should be like this 72 | # 73 | # Archive: $BadZIP 74 | # Length Date Time Name 75 | # --------- ---------- ----- ---- 76 | # 15 2020-06-01 16:03 data.txt 77 | # --------- ------- 78 | # 15 1 file 79 | # EOM 80 | 81 | like $stdout, qr/:03\s+data.txt/, "unzip -l shows data.txt"; 82 | 83 | 84 | is $stderr, "", "No stderr"; 85 | 86 | ok ! -e "data.txt", "data.txt does not exist yet"; 87 | 88 | ($status, $stdout, $stderr) = run("unzip $BadZIP"); 89 | 90 | is $status, 0, "unzip returned zero for extraction"; 91 | is $stderr, "", "stderr empty"; 92 | like $stdout, qr/extracting: data.txt/, "stdout ok"; 93 | 94 | ok -e "data.txt", "data.txt now exists"; 95 | is readFile("data.txt"), "this is a test\n", "File contents ok"; 96 | } 97 | 98 | chdir $HERE ; 99 | 100 | exit ; 101 | 102 | sub removeHour 103 | { 104 | my $string = shift; 105 | $string =~ s/15 2020-06-01 \d\d:03 data.txt/15 2020-06-01 XX:03 data.txt/; 106 | 107 | $string; 108 | } 109 | 110 | sub readFile 111 | { 112 | my $f = shift ; 113 | 114 | my @strings ; 115 | 116 | open (F, "<$f") 117 | or die "Cannot open $f: $!\n" ; 118 | binmode F; 119 | @strings = ; 120 | close F ; 121 | 122 | 123 | return @strings if wantarray ; 124 | return join "", @strings ; 125 | } 126 | 127 | sub run 128 | { 129 | my $command = shift ; 130 | 131 | my $cmd = "$command 2>stderr"; 132 | my $stdout = `$cmd` ; 133 | 134 | my $status = $?; 135 | my $stderr = readFile('stderr') ; 136 | 137 | return ($status, $stdout, $stderr); 138 | } 139 | -------------------------------------------------------------------------------- /fix-onedrive-zip: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # fix-onedrive-zip 4 | # 5 | # Fix OneDrive/Windows Zip files larger than 4Gig that have an invalid 6 | # 'Total Number of Disks' field in the 'ZIP64 End Central Directory 7 | # Locator'. The value in this field should be 1, but OneDrive/Windows sets 8 | # it to 0. This makes it difficult to work with these files using standard 9 | # unzip utilities. 10 | # 11 | # This program changes the 'Total Number of Disks' field value to 1. 12 | # 13 | # Copyright (c) 2020-2025 Paul Marquess. All rights reserved. 14 | # 15 | # This program is free software; you can redistribute it and/or modify it 16 | # under the same terms as Perl itself. 17 | 18 | use strict; 19 | use warnings; 20 | 21 | use Fcntl qw(SEEK_SET SEEK_END); 22 | use Getopt::Long; 23 | 24 | # Signatures for the headers we need to check 25 | use constant ZIP_LOCAL_HDR_SIG => 0x04034b50; 26 | use constant ZIP_END_CENTRAL_HDR_SIG => 0x06054b50; 27 | use constant ZIP64_END_CENTRAL_LOC_HDR_SIG => 0x07064b50; 28 | 29 | sub Seek; 30 | sub Read; 31 | 32 | my $VERSION = '1.02' ; 33 | my $dry_run ; 34 | 35 | BEGIN { 36 | # Check for a 32-bit Perl 37 | if (!eval { pack "Q", 1 }) { 38 | warn "The perl executable you are running is 32-bit.\n" . 39 | "You need to install a 64-bit perl executable to continue\n"; 40 | exit(1); 41 | } 42 | } 43 | 44 | GetOptions ("dry-run" => \$dry_run, 45 | "help" => \&Usage) 46 | or Usage("Error in command line arguments\n"); 47 | 48 | Usage() 49 | unless @ARGV >= 1; 50 | 51 | # run a quick sanility test on all the zip files 52 | for my $filename (@ARGV) 53 | { 54 | # check exists & can read 55 | open my $fh, "+<$filename" 56 | or die "Error: Cannot open '$filename': $!\n"; 57 | 58 | # check no empty & 59 | my $fileSize = -s $filename ; 60 | 61 | die "Error: zip file '$filename' is empty\n" 62 | if $fileSize == 0; 63 | } 64 | 65 | for my $filename (@ARGV) 66 | { 67 | print "\nChecking '$filename'\n"; 68 | open my $fh, "+<$filename" 69 | or die "Cannot open '$filename': $!\n"; 70 | 71 | my $data = Read $filename, $fh, 4; 72 | 73 | my $sig = unpack("V", $data) ; 74 | 75 | die "Error: No Zip signature at start of '$filename'\n" 76 | unless $sig == ZIP_LOCAL_HDR_SIG ; 77 | 78 | # Assume no comment or other trailing data 79 | # The last two things in the file are the Z64 & EOCD records 80 | 81 | Seek $filename, $fh, -42 ; 82 | 83 | $data = Read $filename, $fh, 42; 84 | 85 | my $eocd = substr($data, 20); 86 | my $eocd_sig = unpack("V", substr($eocd, 0, 4)) ; 87 | 88 | die "Error: Cannot find Zip signature at end of '$filename'\n" 89 | unless $eocd_sig == ZIP_END_CENTRAL_HDR_SIG ; 90 | 91 | my $offset = unpack("VV", substr($eocd, 16, 4)) ; 92 | 93 | die sprintf "Error: bad offset 0x%X at end of '$filename'\n", $offset 94 | unless $offset == 0xFFFFFFFF ; 95 | 96 | my $z64_sig = unpack("V", substr($data, 0, 4)) ; 97 | 98 | die "Error: Cannot find Zip64 signature at end of '$filename'\n" 99 | unless $z64_sig == ZIP64_END_CENTRAL_LOC_HDR_SIG ; 100 | 101 | my $total_disks = unpack("V", substr($data, 16, 4)) ; 102 | 103 | if ($total_disks == 1) 104 | { 105 | print "Nothing to do: 'Total Number of Disks' field is already 1\n"; 106 | next 107 | } 108 | 109 | if ($total_disks != 0) 110 | { 111 | die "Error: 'Total Number of Disks' field is $total_disks\n"; 112 | } 113 | 114 | Seek $filename, $fh, -42 + 16 ; 115 | 116 | if ($dry_run) 117 | { 118 | print "Dry-Run: No change made to '$filename'\n"; 119 | } 120 | else 121 | { 122 | print $fh pack "V", 1 ; 123 | print "Updated '$filename'\n"; 124 | } 125 | } 126 | 127 | sub Seek 128 | { 129 | my $filename = shift; 130 | my $fh = shift ; 131 | my $offset = shift ; 132 | 133 | seek $fh, $offset, SEEK_END 134 | or die "Cannot seek '$filename': $!\n" ; 135 | } 136 | 137 | sub Read 138 | { 139 | my $filename = shift ; 140 | my $fh = shift; 141 | my $size = shift ; 142 | 143 | my $data ; 144 | 145 | read($fh, $data, $size) == $size 146 | or die "Cannot read from '$filename': $!\n" ; 147 | 148 | return $data; 149 | } 150 | 151 | sub Usage 152 | { 153 | print <<'EOM'; 154 | Usage: fix-onedrive-zip [--dry-run] file1.zip [file2.zip...] 155 | 156 | Fix OneDrive/Windows Zip files larger than 4Gig that have an invalid 'Total 157 | Number of Disks' field in the 'ZIP64 End Central Directory Locator'. The 158 | value in this field should be 1, but OneDrive/Windows sets it to 0. This 159 | makes it difficult to work with these files using standard unzip utilities. 160 | 161 | This program changes the 'Total Number of Disks' field value to 1. 162 | 163 | See https://github.com/pmqs/Fix-OneDrive-Zip for support. 164 | 165 | Copyright (c) 2020-2025 Paul Marquess (pmqs@cpan.org). All rights reserved. 166 | 167 | This program is free software; you can redistribute it and/or modify it 168 | under the same terms as Perl itself. 169 | 170 | EOM 171 | exit; 172 | } 173 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fix-OneDrive-Zip 2 | 3 | [![Linux build](https://github.com/pmqs/Fix-OneDrive-Zip/workflows/Linux%20build/badge.svg)](https://github.com/pmqs/Fix-OneDrive-Zip/actions) 4 | [![MacOS build](https://github.com/pmqs/Fix-OneDrive-Zip/workflows/Macos%20build/badge.svg)](https://github.com/pmqs/Fix-OneDrive-Zip/actions) 5 | [![Windows build](https://github.com/pmqs/Fix-OneDrive-Zip/workflows/Windows%20build/badge.svg)](https://github.com/pmqs/Fix-OneDrive-Zip/actions) 6 | [![FreeBSD](https://api.cirrus-ci.com/github/pmqs/Fix-OneDrive-Zip.svg?task=FreeBSD)](https://cirrus-ci.com/github/pmqs/Fix-OneDrive-Zip?task=FreeBSD) 7 | 8 | This program fixes an issue with Zip files larger than 4 Gig that have been created by either 9 | `OneDrive` or the Windows 10 right-click action "`Send-To/Compressed 10 | (zip) folder`". At the time of writing these Zip files cannot be unzipped 11 | using some of the well-know Zip archivers. 12 | 13 | For a really detailed summary of the issue, see 14 | [Does Microsoft OneDrive export large ZIP files that are corrupt?](https://www.bitsgalore.org/2020/03/11/does-microsoft-onedrive-export-large-ZIP-files-that-are-corrupt). 15 | 16 | This program automates the manual process described in the referenced page. 17 | It has been tested on Windows, Linux, MacOS & FreeBSD. 18 | 19 | > [!NOTE] 20 | > 21 | > 1. It may be possible to work around this issue by updating the archiving program you are using to the latest version. No guarantees. 22 | > 23 | > 2. It is strongly recommended to take a backup copy of your original zip file before running this program. 24 | > 25 | > 3. You need a 64-bit build of `Perl` installed on your system to run this program. 26 | > 27 | 28 | ## Usage 29 | 30 | perl fix-onedrive-zip [--dry-run] file1.zip [file2.zip...] 31 | 32 | The `--dry-run` option will simulate running of the program without making 33 | any changes to the Zip file. 34 | 35 |
36 |

Notes for Windows Users

37 | 38 | If you are running Windows and don't know what a Perl script is, or how to run one, this section 39 | will walk you through the process. 40 | 41 |
42 | Step 1: Check if you already have Perl installed 43 |

44 | 45 | The `fix-onedrive-zip` script is written in `Perl`. To run it on your PC you need to have 46 | the `perl` executable installed. 47 | 48 | To check if it is already installed, create a terminal window by typing `Windows+R`. 49 | In the pop-up window type `cmd`. You should now have a terminal window open. 50 | 51 | Type `perl -v`. 52 | If `perl` is installed you should see text like this. The Perl version doesn't matter. 53 | 54 | ``` 55 | C:\Users\me>perl -v 56 | 57 | This is perl 5, version 32, subversion 1 (v5.32.1) built for MSWin32-x64-multi-thread 58 | 59 | Copyright 1987-2021, Larry Wall 60 | 61 | Perl may be copied only under the terms of either the Artistic License or the 62 | GNU General Public License, which may be found in the Perl 5 source kit. 63 | 64 | Complete documentation for Perl, including FAQ lists, should be found on 65 | this system using "man perl" or "perldoc perl". If you have access to the 66 | Internet, point your browser at http://www.perl.org/, the Perl Home Page. 67 | ``` 68 | 69 | If you don't have `perl`, the output will look like this 70 | 71 | ``` 72 | 'perl' is not recognized as an internal or external command, 73 | operable program or batch file. 74 | ``` 75 |
76 | 77 |
78 | Step 2: Install Perl if you don't already have it 79 |

80 | 81 | There are a number of Perl executables available for Windows. 82 | For this tutorial I've used [Strawberry Perl](https://strawberryperl.com/), but there are others available. 83 | 84 | Use the instructions [here](https://www.perltutorial.org/setting-up-perl-development-environment/) to install the 64-bit "*Recommended version*" of `perl` from the [Strawberry Perl](https://strawberryperl.com/) site. 85 | 86 | Once the installation is complete, run `Step 1`, above, to double-check that the perl works ok 87 | from the command-line in a terminal window. 88 |
89 | 90 |
91 | Step 3: Download the fix-onedrive-zip script 92 |

93 | 94 | You now need to get the `fix-onedrive-zip` script downloaded from GitHub and stored on your PC. In a browser navigate to 95 | [here](https://github.com/pmqs/Fix-OneDrive-Zip/blob/master/fix-onedrive-zip) and 96 | select the "`Download raw file`" icon, as highlighted below 97 | 98 | ![](assets/download.png) 99 | 100 | That should download the file `fix-onedrive-zip` into your `Downloads` directory. 101 |
102 | 103 |
104 | 105 | Step 4: Running the fix-onedrive-zip script 106 |

107 | 108 | The easiest approach to running this script if you are not confortable with running from the command-line is to 109 | put the `fix-onedrive-zip` script and the zip file you want to fix in the same folder. Lets assume you have both stored in the folder `C:\fixzip` and the name of the OneDrive zip file you want to fix is `myfile.zip`. 110 | 111 | Start by creating a terminal window by typing `Windows+R` and typing `cmd` in the pop-up window. 112 | 113 | Now run the command below in the terminal window to move to the folder where your zip file is stored, replacing 114 | `C:\fixzip` with the name of the folder you are using 115 | 116 | ``` 117 | cd C:\fixzip 118 | ``` 119 | 120 | You can now run the `fix-onedrive-zip` script by typing this in the terminal window. Remember to change `myfile.zip` to the name of the zip file you want fixed. 121 | 122 | ``` 123 | perl fix-onedrive-zip myfile.zip 124 | ``` 125 | 126 | That should have fixed your zip file. 127 |
128 |
129 | 130 | 131 |
132 |

What if this program does not fix the issue?

133 | 134 | 135 | The most common issue reported with this script is the following error 136 | message: 137 | 138 | ```Error: Cannot find Zip signature at end of 'somefile.zip'``` 139 | 140 | To understand what this message means you first need to know a little bit 141 | about the structure of the metadata in a zip file. 142 | 143 | At the start of a zip file 144 | there are 4 bytes called the "`local file header signature`". The majority of metedata values in a zip file are stored in little-endian byte order, so these 4 bytes are unpacked as the litte-endian value `0x04034b50`. For this error case these 4 145 | signature bytes *will* be present, so the script knows it likely dealing 146 | with a zip file. 147 | 148 | Once that initial test is done, the script moves to 22 bytes before the end 149 | of the file and checks that the 4 bytes of the "`end of central dir 150 | signature`" (little-endian value `0x06054b50`) are present. In this case 151 | it *doesn't* find these signature bytes. 152 | 153 | This program can only work with a well-formed zip file, so it now terminates immediately with the error message shown above. 154 | 155 | The root-cause for this error is typically a zip file that has either been truncated or partially corrupted (i.e. the end the file has been overwritten with random data). 156 | 157 |
158 |

Strategies for recovering data

159 | 160 | 161 | The most straightforward way to deal with a truncated/corrupt zip file is to download a fresh copy of the zip file. 162 | 163 | If downloading is not an option, it may be possible to recover some/all of the zip file payload data. It just depends on how badly damaged the file is. Be aware - if payload data has been overwritten or is absent there is no way that to retrieve this data from the zip file. 164 | 165 | There are plenty of articles available online that discuss recovering data from corrupt zip files, so I'll only mention that the [Info-ZIP](https://infozip.sourceforge.net/) implementaion of `zip` (most Unix/Mac systems ship with this program) has two commandline options, `-F` and `-FF`, that can be used to attempt to fix zip files. 166 | 167 |
168 |
169 | 170 | 171 |
172 |

Zip File Technical Details

173 | 174 | If you want to understand more about the internal structure of Zip files, 175 | the primary reference is 176 | [APPNOTE.TXT](https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT). 177 | 178 | The issue with `OneNote`/`Windows` Zip files larger than 4 Gig is they 179 | have an invalid `Total Number of Disks` field in the 180 | `ZIP64 End Central Directory Locator` record (see [APPNOTE.TXT](https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT) version 6.3.10, section 4.3.15). 181 | The value in this field should be `1`, but `OneDrive`/`Windows` incorrectly sets it to `0`. 182 | 183 | This program simply changes the `Total Number of Disks` field value to `1` 184 | if it finds it set to `0` in a Zip file. 185 | 186 |
187 | 188 | ## Support 189 | 190 | If you have any problem running this program, or have suggestions or questions, 191 | please report them at https://github.com/pmqs/Fix-OneDrive-Zip/issues. 192 | 193 | ## Copyright 194 | 195 | Copyright (c) 2020-2025 Paul Marquess (pmqs@cpan.org). All rights reserved. 196 | 197 | This program is free software; you can redistribute it and/or modify it 198 | under the same terms as Perl itself. 199 | --------------------------------------------------------------------------------