escape.hpp
Go to the documentation of this file.
/*********************************************************************/
// dar - disk archive - a backup/restoration program
// Copyright (C) 2002-2023 Denis Corbin
//
// 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.
//
// 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.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// to contact the author, see the AUTHOR file
/*********************************************************************/
#ifndef ESCAPE_HPP
#define ESCAPE_HPP
#include "../my_config.h"
extern "C"
{
#if HAVE_LIMITS_H
#include <limits.h>
#endif
}
#include <set>
#include "generic_file.hpp"
#define ESCAPE_FIXED_SEQUENCE_NORMAL 0xAD
#define ESCAPE_FIXED_SEQUENCE_SPARSE_FILE 0xAE
#define MAX_BUFFER_SIZE 102400
#ifdef SSIZE_MAX
#if SSIZE_MAX < MAX_BUFFER_SIZE
#undef MAX_BUFFER_SIZE
#define MAX_BUFFER_SIZE SSIZE_MAX
#endif
#endif
namespace libdar
{
class escape : public generic_file
{
public:
enum sequence_type
{
seqt_undefined,
seqt_not_a_sequence,
seqt_file,
seqt_ea,
seqt_catalogue,
seqt_data_name,
seqt_file_crc,
seqt_ea_crc,
seqt_changed,
seqt_dirty,
seqt_failed_backup,
seqt_fsa,
seqt_fsa_crc,
seqt_delta_sig,
seqt_in_place
};
// the archive layout of marks is for each entry:
// #seqt_file# <inode> [<file data> [#seqt_changed# <new copy of data> [...] ] #seqt_file_crc# <CRC>[#seqt_dirty#]] [#seqt_ea# <EA> #seqt_ea_crc# <CRC>]
// this previous sequence that we will call <SEQ> is repeated for each file, then on the overall archive we have :
// #seqt_data_name# <data_name> <SEQ> ... <SEQ> #seqt_catalogue# <catalogue> <terminator>
// the provided "below" object must exist during the whole live of the escape object,
// the escape object does not own this "below" object
// it must be destroyed by the caller/creator of the escape object.
// constructors & destructors
escape(generic_file *below,
const std::set<sequence_type> & x_unjumpable
);
escape(const escape & ref) : generic_file(ref) { copy_from(ref); };
escape(escape && ref) noexcept : generic_file(std::move(ref)) { nullifyptr(); move_from(std::move(ref)); };
escape & operator = (const escape & ref);
escape & operator = (escape && ref) noexcept { generic_file::operator = (std::move(ref)); move_from(std::move(ref)); return *this; };
~escape();
// escape specific routines
void add_mark_at_current_position(sequence_type t);
bool skip_to_next_mark(sequence_type t, bool jump);
bool next_to_read_is_mark(sequence_type t);
bool next_to_read_is_which_mark(sequence_type & t);
void add_unjumpable_mark(sequence_type t) { if(is_terminated()) throw SRC_BUG; unjumpable.insert(t); };
void remove_unjumpable_mark(sequence_type t);
bool is_unjumpable_mark(sequence_type t) const { return unjumpable.find(t) != unjumpable.end(); };
void clear_all_unjumpable_marks() { unjumpable.clear(); };
// generic_file inherited routines
// NOTA: Nothing is done to prevent skip* operation to put the read cursor in the middle of an escape sequence and
// thus incorrectly consider it as normal data. Such event should only occure upon archive corruption and will be detected
// by checksum mechanisms.
virtual bool skippable(skippability direction, const infinint & amount) override;
virtual bool skip(const infinint & pos) override;
virtual bool skip_to_eof() override;
virtual bool skip_relative(S_I x) override;
virtual bool truncatable(const infinint & pos) const override { return x_below->truncatable(pos); };
virtual infinint get_position() const override;
protected:
virtual void inherited_read_ahead(const infinint & amount) override;
virtual U_I inherited_read(char *a, U_I size) override;
virtual void inherited_write(const char *a, U_I size) override;
virtual void inherited_truncate(const infinint & pos) override;
virtual void inherited_sync_write() override { flush_write(); };
virtual void inherited_flush_read() override { flush_write(); clean_read(); };
virtual void inherited_terminate() override { flush_or_clean(); };
void change_fixed_escape_sequence(unsigned char value) { fixed_sequence[0] = value; };
bool has_escaped_data_since_last_skip() const { return escaped_data_count_since_last_skip > 0; };
private:
//-- constants
static constexpr U_I ESCAPE_SEQUENCE_LENGTH = 6;
static constexpr U_I INITIAL_WRITE_BUFFER_SIZE = 2*ESCAPE_SEQUENCE_LENGTH;
static constexpr U_I INITIAL_READ_BUFFER_SIZE = MAX_BUFFER_SIZE;
static const infinint READ_BUFFER_SIZE_INFININT;
static const unsigned char usual_fixed_sequence[ESCAPE_SEQUENCE_LENGTH];
//-- variables
generic_file *x_below;
U_I write_buffer_size;
char write_buffer[INITIAL_WRITE_BUFFER_SIZE];
U_I already_read;
bool read_eof;
U_I escape_seq_offset_in_buffer;
char* read_buffer;
U_I read_buffer_size;
U_I read_buffer_alloc;
std::set<sequence_type> unjumpable;
unsigned char fixed_sequence[ESCAPE_SEQUENCE_LENGTH];
infinint escaped_data_count_since_last_skip;
infinint below_position;
//-- routines
void set_fixed_sequence_for(sequence_type t) { fixed_sequence[ESCAPE_SEQUENCE_LENGTH - 1] = type2char(t); };
void check_below() const { if(x_below == nullptr) throw SRC_BUG; };
void clean_read();
void flush_write();
void flush_or_clean()
{
switch(get_mode())
{
case gf_read_only:
clean_read();
break;
case gf_write_only:
case gf_read_write:
flush_write();
break;
default:
throw SRC_BUG;
}
};
void nullifyptr() noexcept { x_below = nullptr; };
void copy_from(const escape & ref);
void move_from(escape && ref) noexcept;
bool mini_read_buffer();
//-- static routine(s)
// some convertion routines
static char type2char(sequence_type x);
static sequence_type char2type(char x);
static U_I trouve_amorce(const char *a, U_I size, const unsigned char escape_sequence[ESCAPE_SEQUENCE_LENGTH]);
static U_I remove_data_marks_and_stop_at_first_real_mark(char *a, U_I size, U_I & delta, const unsigned char escape_sequence[ESCAPE_SEQUENCE_LENGTH]);
};
} // end of namespace
#endif
libdar::generic_file::generic_file
generic_file(gf_mode m)
main constructor
Definition: generic_file.hpp:80
libdar::generic_file::operator=
generic_file & operator=(const generic_file &ref)
assignment operator
Definition: generic_file.hpp:89
libdar::generic_file::is_terminated
bool is_terminated() const
Definition: generic_file.hpp:327
libdar::generic_file::get_mode
gf_mode get_mode() const
retreive the openning mode for this object
Definition: generic_file.hpp:109
generic_file.hpp
class generic_file is defined here as well as class fichier
libdar::gf_write_only
@ gf_write_only
write only access
Definition: gf_mode.hpp:46
libdar::gf_read_only
@ gf_read_only
read only access
Definition: gf_mode.hpp:45
libdar::gf_read_write
@ gf_read_write
read and write access
Definition: gf_mode.hpp:47
libdar
libdar namespace encapsulate all libdar symbols
Definition: archive.hpp:47