2025-02-21 11:31:04 +01:00
|
|
|
/* Lziprecover - Data recovery tool for the lzip format
|
|
|
|
Copyright (C) 2009-2021 Antonio Diaz Diaz.
|
2025-02-21 10:09:52 +01:00
|
|
|
|
2025-02-21 11:31:04 +01:00
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
2025-02-21 10:09:52 +01:00
|
|
|
|
2025-02-21 11:31:04 +01:00
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
2025-02-21 10:09:52 +01:00
|
|
|
|
2025-02-21 11:31:04 +01:00
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2025-02-21 10:09:52 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
#define _FILE_OFFSET_BITS 64
|
|
|
|
|
2025-02-21 11:26:24 +01:00
|
|
|
#include <algorithm>
|
2025-02-21 10:09:52 +01:00
|
|
|
#include <cerrno>
|
|
|
|
#include <climits>
|
|
|
|
#include <cstdio>
|
|
|
|
#include <cstring>
|
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
#include <stdint.h>
|
2025-02-21 10:12:48 +01:00
|
|
|
#include <unistd.h>
|
2025-02-21 10:09:52 +01:00
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
#include "lzip.h"
|
2025-02-21 11:29:36 +01:00
|
|
|
#include "lzip_index.h"
|
2025-02-21 10:09:52 +01:00
|
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
void first_filename( const std::string & input_filename,
|
|
|
|
const std::string & default_output_filename,
|
2025-02-21 11:26:24 +01:00
|
|
|
const int max_digits )
|
2025-02-21 10:09:52 +01:00
|
|
|
{
|
2025-02-21 11:26:24 +01:00
|
|
|
output_filename = default_output_filename.empty() ?
|
|
|
|
input_filename : default_output_filename;
|
2025-02-21 10:09:52 +01:00
|
|
|
int b = output_filename.size();
|
|
|
|
while( b > 0 && output_filename[b-1] != '/' ) --b;
|
2025-02-21 11:23:19 +01:00
|
|
|
output_filename.insert( b, "rec1" );
|
|
|
|
if( max_digits > 1 ) output_filename.insert( b + 3, max_digits - 1, '0' );
|
2025-02-21 10:09:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-02-21 11:26:24 +01:00
|
|
|
bool next_filename( const int max_digits )
|
2025-02-21 10:09:52 +01:00
|
|
|
{
|
2025-02-21 11:29:36 +01:00
|
|
|
if( verbosity >= 1 )
|
|
|
|
{
|
|
|
|
std::printf( "Member '%s' done \n", output_filename.c_str() );
|
|
|
|
std::fflush( stdout );
|
|
|
|
}
|
2025-02-21 10:09:52 +01:00
|
|
|
int b = output_filename.size();
|
|
|
|
while( b > 0 && output_filename[b-1] != '/' ) --b;
|
2025-02-21 11:13:34 +01:00
|
|
|
for( int i = b + max_digits + 2; i > b + 2; --i ) // "rec<max_digits>"
|
2025-02-21 10:09:52 +01:00
|
|
|
{
|
|
|
|
if( output_filename[i] < '9' ) { ++output_filename[i]; return true; }
|
|
|
|
else output_filename[i] = '0';
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2025-02-21 11:29:36 +01:00
|
|
|
} // end namespace
|
2025-02-21 10:09:52 +01:00
|
|
|
|
|
|
|
|
2025-02-21 11:29:36 +01:00
|
|
|
int split_file( const std::string & input_filename,
|
|
|
|
const std::string & default_output_filename, const bool force )
|
2025-02-21 10:09:52 +01:00
|
|
|
{
|
|
|
|
struct stat in_stats;
|
2025-02-21 11:31:04 +01:00
|
|
|
const int infd =
|
|
|
|
open_instream( input_filename.c_str(), &in_stats, false, true );
|
2025-02-21 10:09:52 +01:00
|
|
|
if( infd < 0 ) return 1;
|
|
|
|
|
2025-02-21 11:29:36 +01:00
|
|
|
Lzip_index lzip_index( infd, true, true, true, true );
|
|
|
|
if( lzip_index.retval() != 0 )
|
2025-02-21 10:09:52 +01:00
|
|
|
{
|
2025-02-21 11:29:36 +01:00
|
|
|
show_file_error( input_filename.c_str(), lzip_index.error().c_str() );
|
|
|
|
return lzip_index.retval();
|
|
|
|
}
|
|
|
|
// verify last member
|
|
|
|
const Block b = lzip_index.mblock( lzip_index.members() - 1 );
|
|
|
|
long long mpos = b.pos();
|
|
|
|
long long msize = b.size();
|
|
|
|
long long failure_pos = 0;
|
|
|
|
if( !safe_seek( infd, mpos ) ) return 1;
|
|
|
|
if( test_member_from_file( infd, msize, &failure_pos ) == 1 )
|
|
|
|
{ // corrupt or fake trailer
|
|
|
|
while( true )
|
2025-02-21 10:09:52 +01:00
|
|
|
{
|
2025-02-21 11:29:36 +01:00
|
|
|
mpos += failure_pos; msize -= failure_pos;
|
|
|
|
if( msize < min_member_size ) break; // trailing data
|
|
|
|
if( !safe_seek( infd, mpos ) ) return 1;
|
|
|
|
if( test_member_from_file( infd, msize, &failure_pos ) != 1 ) break;
|
2025-02-21 10:09:52 +01:00
|
|
|
}
|
2025-02-21 11:29:36 +01:00
|
|
|
lzip_index = Lzip_index( infd, true, true, true, true, mpos );
|
|
|
|
if( lzip_index.retval() != 0 )
|
2025-02-21 10:09:52 +01:00
|
|
|
{
|
2025-02-21 11:29:36 +01:00
|
|
|
show_file_error( input_filename.c_str(), lzip_index.error().c_str() );
|
|
|
|
return lzip_index.retval();
|
2025-02-21 10:09:52 +01:00
|
|
|
}
|
2025-02-21 11:29:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if( !safe_seek( infd, 0 ) ) return 1;
|
|
|
|
int max_digits = 1;
|
|
|
|
for( long i = lzip_index.blocks( true ); i >= 10; i /= 10 ) ++max_digits;
|
|
|
|
first_filename( input_filename, default_output_filename, max_digits );
|
|
|
|
|
|
|
|
long long stream_pos = 0; // first pos not yet written to file
|
|
|
|
set_signal_handler();
|
|
|
|
for( long i = 0; i < lzip_index.members(); ++i )
|
|
|
|
{
|
|
|
|
const Block & mb = lzip_index.mblock( i );
|
|
|
|
if( mb.pos() > stream_pos ) // gap
|
2025-02-21 10:09:52 +01:00
|
|
|
{
|
2025-02-21 11:31:04 +01:00
|
|
|
if( !open_outstream( force, true, false, false ) ) return 1;
|
2025-02-21 11:29:36 +01:00
|
|
|
if( !copy_file( infd, outfd, mb.pos() - stream_pos ) ||
|
|
|
|
close_outstream( &in_stats ) != 0 )
|
|
|
|
cleanup_and_fail( 1 );
|
|
|
|
next_filename( max_digits );
|
2025-02-21 10:09:52 +01:00
|
|
|
}
|
2025-02-21 11:31:04 +01:00
|
|
|
if( !open_outstream( force, true, false, false ) ) return 1; // member
|
2025-02-21 11:29:36 +01:00
|
|
|
if( !copy_file( infd, outfd, mb.size() ) ||
|
|
|
|
close_outstream( &in_stats ) != 0 )
|
|
|
|
cleanup_and_fail( 1 );
|
|
|
|
next_filename( max_digits );
|
|
|
|
stream_pos = mb.end();
|
2025-02-21 10:09:52 +01:00
|
|
|
}
|
2025-02-21 11:29:36 +01:00
|
|
|
if( lzip_index.file_size() > stream_pos ) // trailing data
|
2025-02-21 11:13:34 +01:00
|
|
|
{
|
2025-02-21 11:31:04 +01:00
|
|
|
if( !open_outstream( force, true, false, false ) ) return 1;
|
2025-02-21 11:29:36 +01:00
|
|
|
if( !copy_file( infd, outfd, lzip_index.file_size() - stream_pos ) ||
|
|
|
|
close_outstream( &in_stats ) != 0 )
|
|
|
|
cleanup_and_fail( 1 );
|
|
|
|
next_filename( max_digits );
|
2025-02-21 11:13:34 +01:00
|
|
|
}
|
2025-02-21 11:29:36 +01:00
|
|
|
close( infd );
|
2025-02-21 10:09:52 +01:00
|
|
|
return 0;
|
|
|
|
}
|