From bfe1c9e528f1db429020e40e15b2483d1ec32b75 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 16 Jun 2023 13:13:28 +0200 Subject: Merging upstream version 1.24~pre1. Signed-off-by: Daniel Baumann --- dump_remove.cc | 136 ++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 102 insertions(+), 34 deletions(-) (limited to 'dump_remove.cc') diff --git a/dump_remove.cc b/dump_remove.cc index 37f7f00..92b5e3d 100644 --- a/dump_remove.cc +++ b/dump_remove.cc @@ -1,5 +1,5 @@ /* Lziprecover - Data recovery tool for the lzip format - Copyright (C) 2009-2022 Antonio Diaz Diaz. + Copyright (C) 2009-2023 Antonio Diaz Diaz. 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 @@ -32,14 +32,12 @@ #include "lzip_index.h" -// If strip is false, dump to outfd members/gaps/tdata in member_list. -// If strip is true, dump to outfd members/gaps/tdata not in member_list. +/* If strip is false, dump to outfd members/gaps/tdata in member_list. + If strip is true, dump to outfd members/gaps/tdata not in member_list. */ int dump_members( const std::vector< std::string > & filenames, const std::string & default_output_filename, - const Member_list & member_list, const bool force, - bool ignore_errors, bool ignore_trailing, - const bool loose_trailing, const bool strip, - const bool to_stdout ) + const Cl_options & cl_opts, const Member_list & member_list, + const bool force, const bool strip, const bool to_stdout ) { if( to_stdout || default_output_filename.empty() ) outfd = STDOUT_FILENO; else @@ -48,14 +46,13 @@ int dump_members( const std::vector< std::string > & filenames, set_signal_handler(); if( !open_outstream( force, false, false, false ) ) return 1; } - if( ( strip || !member_list.tdata || member_list.damaged || member_list.range() ) && + if( ( strip || !member_list.tdata || member_list.damaged || + member_list.empty || member_list.range() ) && !check_tty_out() ) return 1; // check tty except for --dump=tdata unsigned long long copied_size = 0, stripped_size = 0; unsigned long long copied_tsize = 0, stripped_tsize = 0; long members = 0, smembers = 0; int files = 0, tfiles = 0, retval = 0; - if( member_list.damaged ) ignore_errors = true; - if( member_list.tdata ) ignore_trailing = true; bool stdin_used = false; for( unsigned i = 0; i < filenames.size(); ++i ) { @@ -68,8 +65,8 @@ int dump_members( const std::vector< std::string > & filenames, open_instream( input_filename, &in_stats, false, true ); if( infd < 0 ) { set_retval( retval, 1 ); continue; } - const Lzip_index lzip_index( infd, ignore_trailing, loose_trailing, - ignore_errors, ignore_errors ); + const Lzip_index lzip_index( infd, cl_opts, cl_opts.ignore_errors, + cl_opts.ignore_errors ); if( lzip_index.retval() != 0 ) { show_file_error( input_filename, lzip_index.error().c_str() ); @@ -77,7 +74,7 @@ int dump_members( const std::vector< std::string > & filenames, close( infd ); continue; } - if( !safe_seek( infd, 0 ) ) cleanup_and_fail( 1 ); + if( !safe_seek( infd, 0, input_filename ) ) cleanup_and_fail( 1 ); const long blocks = lzip_index.blocks( false ); // not counting tdata long long stream_pos = 0; // first pos not yet read from file long gaps = 0; @@ -92,7 +89,7 @@ int dump_members( const std::vector< std::string > & filenames, member_list.includes( j + gaps, blocks ); if( in == !strip ) { - if( !safe_seek( infd, stream_pos ) || + if( !safe_seek( infd, stream_pos, input_filename ) || !copy_file( infd, outfd, mb.pos() - stream_pos ) ) cleanup_and_fail( 1 ); copied_size += mb.pos() - stream_pos; ++members; @@ -101,14 +98,16 @@ int dump_members( const std::vector< std::string > & filenames, ++gaps; } bool in = member_list.includes( j + gaps, blocks ); // member + if( !in && member_list.empty && lzip_index.dblock( j ).size() == 0 ) + in = true; if( !in && member_list.damaged ) { - if( !safe_seek( infd, mb.pos() ) ) cleanup_and_fail( 1 ); + if( !safe_seek( infd, mb.pos(), input_filename ) ) cleanup_and_fail( 1 ); in = ( test_member_from_file( infd, mb.size() ) != 0 ); // damaged } if( in == !strip ) { - if( !safe_seek( infd, mb.pos() ) || + if( !safe_seek( infd, mb.pos(), input_filename ) || !copy_file( infd, outfd, mb.size() ) ) cleanup_and_fail( 1 ); copied_size += mb.size(); ++members; } @@ -128,7 +127,7 @@ int dump_members( const std::vector< std::string > & filenames, if( member_list.tdata == !strip && trailing_size > 0 && ( !strip || i + 1 >= filenames.size() ) ) // strip all but last { - if( !safe_seek( infd, cdata_size ) || + if( !safe_seek( infd, cdata_size, input_filename ) || !copy_file( infd, outfd, trailing_size ) ) cleanup_and_fail( 1 ); copied_tsize += trailing_size; } @@ -140,7 +139,7 @@ int dump_members( const std::vector< std::string > & filenames, { if( !strip ) { - if( member_list.damaged || member_list.range() ) + if( member_list.damaged || member_list.empty || member_list.range() ) std::fprintf( stderr, "%llu bytes dumped from %ld %s from %d %s.\n", copied_size, members, ( members == 1 ) ? "member" : "members", @@ -150,7 +149,7 @@ int dump_members( const std::vector< std::string > & filenames, } else { - if( member_list.damaged || member_list.range() ) + if( member_list.damaged || member_list.empty || member_list.range() ) std::fprintf( stderr, "%llu bytes stripped from %ld %s from %d %s.\n", stripped_size, smembers, ( smembers == 1 ) ? "member" : "members", @@ -164,15 +163,14 @@ int dump_members( const std::vector< std::string > & filenames, } +/* Remove members, tdata from files in place by opening two descriptors for + each file. */ int remove_members( const std::vector< std::string > & filenames, - const Member_list & member_list, bool ignore_errors, - bool ignore_trailing, const bool loose_trailing ) + const Cl_options & cl_opts, const Member_list & member_list ) { unsigned long long removed_size = 0, removed_tsize = 0; long members = 0; int files = 0, tfiles = 0, retval = 0; - if( member_list.damaged ) ignore_errors = true; - if( member_list.tdata ) ignore_trailing = true; for( unsigned i = 0; i < filenames.size(); ++i ) { const char * const filename = filenames[i].c_str(); @@ -180,8 +178,8 @@ int remove_members( const std::vector< std::string > & filenames, const int infd = open_instream( filename, &in_stats, false, true ); if( infd < 0 ) { set_retval( retval, 1 ); continue; } - const Lzip_index lzip_index( infd, ignore_trailing, loose_trailing, - ignore_errors, ignore_errors ); + const Lzip_index lzip_index( infd, cl_opts, cl_opts.ignore_errors, + cl_opts.ignore_errors ); if( lzip_index.retval() != 0 ) { show_file_error( filename, lzip_index.error().c_str() ); @@ -192,7 +190,7 @@ int remove_members( const std::vector< std::string > & filenames, const int fd = open_truncable_stream( filename, &dummy_stats ); if( fd < 0 ) { close( infd ); set_retval( retval, 1 ); continue; } - if( !safe_seek( infd, 0 ) ) return 1; + if( !safe_seek( infd, 0, filename ) ) return 1; const long blocks = lzip_index.blocks( false ); // not counting tdata long long stream_pos = 0; // first pos not yet written to file long gaps = 0; @@ -207,8 +205,8 @@ int remove_members( const std::vector< std::string > & filenames, if( !member_list.damaged && !member_list.includes( j + gaps, blocks ) ) { if( stream_pos != prev_end && - ( !safe_seek( infd, prev_end ) || - !safe_seek( fd, stream_pos ) || + ( !safe_seek( infd, prev_end, filename ) || + !safe_seek( fd, stream_pos, filename ) || !copy_file( infd, fd, mb.pos() - prev_end ) ) ) { error = true; set_retval( retval, 1 ); break; } stream_pos += mb.pos() - prev_end; @@ -217,17 +215,19 @@ int remove_members( const std::vector< std::string > & filenames, ++gaps; } bool in = member_list.includes( j + gaps, blocks ); // member + if( !in && member_list.empty && lzip_index.dblock( j ).size() == 0 ) + in = true; if( !in && member_list.damaged ) { - if( !safe_seek( infd, mb.pos() ) ) + if( !safe_seek( infd, mb.pos(), filename ) ) { error = true; set_retval( retval, 1 ); break; } in = ( test_member_from_file( infd, mb.size() ) != 0 ); // damaged } if( !in ) { if( stream_pos != mb.pos() && - ( !safe_seek( infd, mb.pos() ) || - !safe_seek( fd, stream_pos ) || + ( !safe_seek( infd, mb.pos(), filename ) || + !safe_seek( fd, stream_pos, filename ) || !copy_file( infd, fd, mb.size() ) ) ) { error = true; set_retval( retval, 1 ); break; } stream_pos += mb.size(); @@ -249,8 +249,8 @@ int remove_members( const std::vector< std::string > & filenames, if( !member_list.tdata ) // copy trailing data { if( stream_pos != cdata_size && - ( !safe_seek( infd, cdata_size ) || - !safe_seek( fd, stream_pos ) || + ( !safe_seek( infd, cdata_size, filename ) || + !safe_seek( fd, stream_pos, filename ) || !copy_file( infd, fd, trailing_size ) ) ) { close( fd ); close( infd ); set_retval( retval, 1 ); break; } stream_pos += trailing_size; @@ -279,7 +279,7 @@ int remove_members( const std::vector< std::string > & filenames, } if( verbosity >= 1 ) { - if( member_list.damaged || member_list.range() ) + if( member_list.damaged || member_list.empty || member_list.range() ) std::fprintf( stderr, "%llu bytes removed from %ld %s from %d %s.\n", removed_size, members, ( members == 1 ) ? "member" : "members", @@ -290,3 +290,71 @@ int remove_members( const std::vector< std::string > & filenames, } return retval; } + + +/* Set to zero in place the first LZMA byte of each member in each file by + opening one rw descriptor for each file. */ +int clear_marking( const std::vector< std::string > & filenames, + const Cl_options & cl_opts ) + { + long cleared_members = 0; + int files = 0, retval = 0; + for( unsigned i = 0; i < filenames.size(); ++i ) + { + const char * const filename = filenames[i].c_str(); + struct stat in_stats; + const int fd = open_truncable_stream( filename, &in_stats ); + if( fd < 0 ) { set_retval( retval, 1 ); continue; } + + const Lzip_index lzip_index( fd, cl_opts, cl_opts.ignore_errors, + cl_opts.ignore_errors ); + if( lzip_index.retval() != 0 ) + { + show_file_error( filename, lzip_index.error().c_str() ); + set_retval( retval, lzip_index.retval() ); + close( fd ); + continue; + } + + enum { bufsize = Lzip_header::size + 1 }; + uint8_t header_buf[bufsize]; + const uint8_t * const p = header_buf; // keep gcc 6.1.0 quiet + const Lzip_header & header = *(const Lzip_header *)p; + uint8_t * const mark = header_buf + Lzip_header::size; + bool write_attempted = false; + for( long j = 0; j < lzip_index.members(); ++j ) // clear the members + { + const Block & mb = lzip_index.mblock( j ); + if( seek_read( fd, header_buf, bufsize, mb.pos() ) != bufsize ) + { show_file_error( filename, "Error reading member header", errno ); + set_retval( retval, 1 ); break; } + if( !header.check( cl_opts.ignore_errors ) ) + { show_file_error( filename, "Member header became corrupt as we read it." ); + set_retval( retval, 2 ); break; } + if( *mark == 0 ) continue; + *mark = 0; write_attempted = true; + if( seek_write( fd, mark, 1, mb.pos() + Lzip_header::size ) != 1 ) + { show_file_error( filename, "Error writing to file", errno ); + set_retval( retval, 1 ); break; } + ++cleared_members; + } + if( close( fd ) != 0 ) + { + show_file_error( filename, "Error closing file", errno ); + set_retval( retval, 1 ); break; + } + if( write_attempted ) + { + struct utimbuf t; + t.actime = in_stats.st_atime; + t.modtime = in_stats.st_mtime; + utime( filename, &t ); + ++files; + } + } + if( verbosity >= 1 ) + std::fprintf( stderr, "%lu %s cleared in %d %s.\n", cleared_members, + ( cleared_members == 1 ) ? "member" : "members", + files, ( files == 1 ) ? "file" : "files" ); + return retval; + } -- cgit v1.2.3