LIBDAR

APPLICATION INTERFACE

TUTORIAL

  for API version 3.0.x


Presentation

Libdar is a library that has been built from source code initially located in dar command line application. The features that libdar provides are the ability to handle Disk ARchive (dar)'s archives, thanks to the following operations:
Note that Disk ARchive has been released under the Gnu General Public License (GPL), and so is the code of libdar. So, to link your code with libdar (statically or dynamically), your application must also be covered by the GPL.

This tutorial will show you how to use libdar from the API. As the dar command line now also uses this API, looking at his code may also be interesting as illustration, in particular the file dar_suite/dar.cpp.

The sample codes provided here are very simple code that could let you see overall process of using libdar, they may or may not compile, I have even not tried to, so just use them as illustration, no more. Note that there is a documentation reference for this API which is built with dar under the directory doc/html if you have Doxygen available and can be consulted on the web.



Let's Start

conventions

Language

Dar and libdar are written in C++, and so is the libdar API. Libdar is thus easily usable with C or C++ code. For other languages, it depends on so many things (calling convention, etc.) that I would just say you are welcome to provide the necessary adaptation layer for any particular language. :-)

Libdar namespace

All libdar symbols are defined under the libdar namespace. You can either add the using namespace libdar; line at the beginning of your source files:

using namespace libdar;

get_version(....);

 or, as we will do in the following examples, you can explicitely use the namespace in front of libdar objects :


libdar::get_version(....);

Exceptions or not Exceptions

For each point we will see two ways of using libdar. One, is using exception, the other is without exceptions. They will be displayed this way :


example code using exceptions


example code not using exceptions


All exceptions used by libdar inherit from the pure virtual class Egeneric. The only method you will need to know about for any exception is the get_message() call, which returns a string explaining the reason of the message in a human language. The type of the error is defined by the class of the exception. Here follows all the exception classes and their meaning:

class libdar::Egeneric
this is the parent class of all exception classes (a pure virtual class)
class libdar::Ememory
exception used when memory has been exhausted
class libdar::Ebug
exception used to signal a bug. A bug is triggered when reaching some code that should never be reached
class libdar::Einfinint
exception used when arithmetic error is detected when operating on infinint
class libdar::Elimitint
exception used when a limitint overflow is detected, the maximum value of the limitint has been exceeded
class libdar::Erange
exception used to signal range error
class libdar::Edeci
exception used to signal convertion problem between infinint and string (decimal representation)
class libdar::Efeature
exception used when a requested feature is not (yet) implemented
class libdar::Ehardware
exception used when hardware problem is found
class libdar::Euser_abort
exception used to signal that the user has aborted the operation
class libdar::Edata
exception used when an error concerning the treated data has been met
class libdar::Escript
exception used when the inter-slice user command returned an error code
class libdar::Elibcall
exception used to signal an error in the arguments given to a libdar call of the API
class libdar::Ecompilation
exception used when a requested fearture has not beed activated at compilation time





 1 - First we *must* check the libdar version


  
    // we include this to be able to display some
    // messages
#include <io.h>

    // we include this header to access lidbar API
#include <dar/libdar.h>

    // all sample code shown will be inside this
    // function for simplicity of the examples
void my_sample_function()
{
   try
   {
      libdar::U_I maj, med, min;

        // first we MUST call get_version()

      libdar::get_version(maj, med, min);

      if(maj != libdar::LIBDAR_COMPILE_TIME_MAJOR ||
         med < libdar::LIBDAR_COMPILE_TIME_MEDIUM)
        throw libdar::Erange("initialization",
        "we are linking against a wrong libdar");
   }

   catch(libdar::Egeneric & e)
   {
      std::cout << e.get_message() << std::endl;
   }
}

  
  
    // we include this to be able to display some
    // messages
#include <io.h>

    // we include this header to access lidbar API
#include <dar/libdar.h>

    // all sample code shown will be inside this
    // function for simplicity of the examples
void my_sample_function()
{

  
libdar::U_I maj, med, min;
   libdar::U_16 excode;
   std::string msg;

    // first we MUST call get_version()

   libdar::get_version_noexcept(maj, med, min,
                                excode, msg);

   if(excode != LIBDAR_NOEXCEPT)
   {
      std::cout << msg << endl;
      return;
   }
 
   if(maj != LIBDAR_COMPILE_TIME_MAJOR ||
     
med < libdar::LIBDAR_COMPILE_TIME_MEDIUM)
   {
      std::cout <<
"we are linking against wrong libdar" << std::endl;
      return;
    }

The get_version* family function must be called for several reasons :

2 - Let's see the compilation time features

once we have called a function of the get_version* family it is possible to access the features activated at compilation time:



void my_sample_function()
{
        // let's continue in the same function

    bool ea;
    bool largefile;
    bool nodump;
    bool special_alloc;
    libdar::U_I bits;
    bool thread_safe;
    bool libz;
    bool libbz2;
    bool libcrypto;

    libdar::get_compile_time_features(ea,
                                      largefile,
                                      nodump,
                                      special_alloc,
                                      bits,
                                      thread_safe,
                                      libz,
                                      libbz2,
                                      libcrypto);

}



 // here there is no difference because no exceptions
 // are thrown by the get_compile_time_feature()
 // function


You can do what you want with the resulting values, like displaying the libdar available feature, or even filter if you don't want to continue when a particular feature is missing. But, that's maybe not necessary to worry here, because libdar will tell you if the operation you ask requires a feature that has not been activated at compilation time thanks to the Ecompile exception or the LIBDAR_ECOMPILATION error code.


3 -User interaction

The generic user_interaction class

To be able to report messages to the user and to be able to ask questions to the user, a special class called user_interaction has been introduced as first argument of the API calls we will see below. Rawly, user_interaction is a pure virtual class from which you can define your own inherited class to have your very own implementation of the interaction with the user (GUI's graphical interaction, for example). You will just have to override four methods which prototypes follow :

void pause (const std::string &message);
this method is called by libdar to request an boolean answer from the user. The question is given in argument and the pause() method must either return if the user agreed the question (said "yes" or "true"), or throw a Euser_abort exception if the user refused the proposition. Don't worry about thowing exception in your code, it will be trapped by libdar if you don't want to manage exceptions, and use libdar in the "no exception" manner.

void warning (const std::string &message);
libdar call this method to display an informational message to the user. It may not always be a warning as the name suggests, sometimes it is just normal information.

std::string get_string (const std::string &message, bool echo);
This call is used to get a arbitrary answer from the user. As this is actually mainly used to get a password from the user (when no password has been suplied for an encrypted archive), the echo argument tells that the user answer shall or shall not be displayed on screen. If echo is set to "false" the implementation of get_string() must hide the character typed by the user in answer to the displayed question.

 user_interactionclone () const;
This is a technical call that must return a copy of the "this" object, like would do the copy constructor. Why not simply use the copy constructor? because libdar may need to keep an internal copy of the object. But the object which class is an inherited class of user_interaction is not know by his real class but through a user_interaction pointer type. So invoking the copy constructor of the user_interaction class will make the new object copied only for the user_interaction part, this may cause a crash when using the object copy. A simple implementation of this method should be something like this (even if you don't want to use exceptions):


user_interaction *my_own_class::clone() const
{
    my_own_class *ret = new my_own_class(*this);
    if(ret == NULL)
        throw Ememory("user_interaction_callback::clone");
    else
        return ret;
}


The callback interaction class

A inherited class from user_interaction called user_interaction_callback proposes an implementation of the user interaction based on callback functions. This just replaces the three interactions methods (pause, warning and get_string) by three normal functions of your choice, which must be given to the user_interaction_callback's constructor and you don't have to consider the clone() method. But you still need to implement theses callback functions. For a real example, I propose you to have a look at what is done for dar's command line. dar's user interaction is done thanks to an object of the user_interaction_callback class and three static functions of the module dar_suite/shell_interaction.cpp

Just a note however about the contextual value present in the arguments of theses callback functions :
 
 
  // our own callback functions.
  // for the illustration of what theses 'context' arguments
  // can be used for we will imagine the situation where
  // multiple windows or multiple threads may each one use
  // libdar. But all share the same callback functions
 
typedef class t_window_type t_win;

  // this is an arbitrary type that here we will say
  // points to a graphical window object wrapped in a C++
  // class.
  // Note that the show() wait_for_click() and so one
  // methods attributed to the t_win class are absolutely
  // imaginary. Any link to an existing class is a pure
  // coincidence...

void warning_callback(const std::string &x, void *context)
{
    (t_win *)(context)->show(x);
}
 
bool answer_callback(const std::string &x, void *context)
{
    click_type ret;

   
(t_win *)(context)->show(x);
    ret = (t_win *)(context)->wait_for_click();

    return ret == click_OK;
}

std::string string_callback(const std::string &x, bool echo, void *context)
{
    (t_win *)(context)->show(x);
    if(!echo)
      (t_win *)(context)->set_hide_typed_char();
    (t_win *)(context)->wait_for_click();
    return (t_win *)(context)->read_text();
}

---------8<-------8<-------8<-------

  // So now each window can have it user_interaction object based on the same

libdar::user_interaction_callback dialog =
        libdar::user_interaction_callback(&warning_callback, &answer_callback, &string_callback,
                                          (void *)get_current_windows_id());

  // just the "context" argument changes, and will be passed asis from the constructor to the callback
  // functions



4 - Masks

Mask are used to define which file are to be considered and which are not to be considered. Libdar implements masks as several classes that all inherit from a pure virtual class that defines the way masks are used. This root class is the class mask and provides the is_covered() method for libdar to know which files to consider. Here follows the different basic masks classes you can use to build very complex masks:


class libdar::mask
the generic class, parent of all masks (a pure virtual class)
class libdar::bool_mask
boolean mask, either always true or false, it matches either all files or no files at all
class libdar::simple_mask
matches as done by the shell on the command lines (see "man 7 glob")
class libdar::regular_mask
matches regular expressions (see "man 7 regex")
class libdar::not_mask
negation of another mask
class libdar::et_mask
makes an *AND* operator between two or more masks
class libdar::ou_mask
makes the *OR* operator between  two or more masks
class lbdar::simple_path_mask
string matches if it is subdir of mask or mask is a subdir of expression
class libdar::same_path_mask
matches if the string is exactly the given mask (no wilde card expression)
class libdar::exclude_dir_mask
matches if string is the given string or a sub directory of it

Let's play with some masks :



      // all files will be elected by this mask
  libdar::bool_mask m1 = true;   

      // all file that match the glob expession "A*~" will match.
      // the second argument of the constructor tell if the match is case sensitive so here
      // any file beginning by 'A' or by 'a' and ending by '~' will be elected by this mask
  libdar::simple_mask m2 = libdar::simple_mask(std::string("A*~"), false);

      // m3 is the negation if m2. This mask will thus match
      // any file that does not begin by 'A' or 'a' and also finish by '~'
  libdar::not_mask m3 = m2;

      // this mask matches any file that is a subdirectory of "/home/joe"
      // and any file that has /home/joe as subdirectory, that is:
      // "/", "/home", "/jome/joe" and any subdirectory are matched.
      // the second argument here too is the case sensitivity (so here
      //  "/HoMe" will not be elected by this mask.
  libdar::simple_path_mask m4 = simple_path_mask("/home/joe", true);

      // now let's do some more complex things:
      // m5 will now match only files that are elected by both m2 AND m4
  libdar::et_mask m5;
  m5.add_mask(m2);
  m5.add_mask(m4);
     
      // we can make more silly things like this, where m5 will select files
      // that match m2 AND m4 AND m3. But m3 = not m2 so now m5 will never
      // match any file...
  m5.add_mask(m3);

      // but we could do the same with a "ou_mask" that realizes the OR operation
      // and we would get an silly equivalent of m1 (a mask that matches any files)
  libdar::ou_mask m6;
  m6.add_mask(m2);
  m6.add_mask(m4);
  m6.add_mask(m3);

      // last point, the NOT, AND and OR operation can be used recurively :
      // even this, is possible where two ask are used as reference for each other !
  libdar::not_mask m7 = m6;
  m6.add_mask(m7);


Now that you see a bit more all the power of masks, you must know that in quite all libdar operations two masks are required:

5 - Let's create a simple archive

Now that we have seen masks and exceptions classes let's start the real thing:
 
  // creating an archive is simple, it is just
  // calling the "create" constructor of the archive
  // class. It may be used for full or differential
  // archive. But we will see differential later.

  // my_arch should have been an object instead of a
  // pointer to an archive object.

libdar::user_interaction_callback dialog = libdar::user_interaction_callback(ptr1, ptr2, ptr3);
  // where ptr1, ptr2 and ptr3 are three callback
  // functions.
libdar::statistics ret;
  // we will see this structure a bit further

libdar::archive *my_arch =
     new libdar::archive(dialog,
     "/home",  // saving all under this "root"
     "/tmp",   // where the slices will go
     NULL,     // we do a full backup for now
     libdar::not_mask(simple_mask("*~", true)),
            // we don't save the files ending with
            // '~' this does not concern directories
     libdar::bool_mask(true),
            // all directories and files not rejected
            // by the previous mask are saved
     "my_archive", 
            // the basename of the slices
     "dar", // dar's slice extensions
     true,  // we allow slice overwriting
     true,  // but ask to be warned in such occurence
     false, // we don't want a verbose output
     false, // nor we want to pause between slices
     true,  // rejected directory will be saved as
            // empty (no directory is rejected so
            // here there is no importance for that
            // parameter)
     libdar::gzip // the archive will be compressed
            // using gzip
     9,     // at maximum compression level
     0,     // no slicing is done,
     0,     // so the first slice size must also be
            // set to zero
     true,  // root EA will be saved if present
     true,  // user EA too
     "",    // no script will be executed between
            // slices (as there is no slicing)
     libdar::crypto_blowfish,
            // the blowfish strong encryption
            // will be used
     "",    // as the password is not given here   
            // (empty string is not a valid password)
            // it will be asked interactively to the
            // user through the dialog
            // user_interaction object
     20480, // the block of encryption will be
            // 20 kbytes
     libdar::not_mask(libdar::simple_mask("*gz")),
            // all files will be compressed except
            // those ending by "gz"
     800,   // file which size is below 800 bytes
            // will not be compressed
     false, // all files will be saved whatever is
            // the nodump flag value
     false, // as we make a full backup this
            // "ignore_owner" parameter is useless
      0,    // hourshift is useless here as we make
            // a full backup
     false, // we will make a real archive not a
            // dry-run operation
     true,  // dar will set back the access time of
            // file it opens, which will change the
            // ctime date of theses files
     false, // we may change of filesystem if
            // necessary
     ret);  // this value is returned by libdar

  // creating an archive is simple, it is just
  // calling the "create" constructor of the archive
  // class. It may be used for full or differential
  // archive. But we will see differential later.

  // my_arch should have been an object instead of a
  // pointer to an archive object.

libdar::user_interaction_callback dialog = libdar::user_interaction_callback(ptr1, ptr2, ptr3);
  // where ptr1, ptr2 and ptr3 are three callback
  // functions.
libdar::statistics ret;
 
// we will see this structure a bit further

U_16 exception,
std::string except_msg;


libdar::archive *my_arch =    
     libdar::create_archive_noexcept(dialog,
 
     "/home",  // saving all under this "root"
     "/tmp",   // where the slices will go
     NULL,     // we do a full backup for now
     libdar::not_mask(simple_mask("*~", true)),
            // we don't save the files ending with
            // '~' this does not concern directories
     libdar::bool_mask(true),
            // all directories and files not rejected
            // by the previous mask are saved
     "my_archive", 
            // the basename of the slices
     "dar", // dar's slice extensions
     true,  // we allow slice overwriting
     true,  // but ask to be warned in such occurence
     false, // we don't want a verbose output
     false, // nor we want to pause between slices
     true,  // rejected directory will be saved as
            // empty (no directory is rejected so
            // here there is no importance for that
            // parameter)
     libdar::gzip // the archive will be compressed
            // using gzip
     9,     // at maximum compression level
     0,     // no slicing is done,
     0,     // so the first slice size must also be
            // set to zero
     true,  // root EA will be saved if present
     true,  // user EA too
     "",    // no script will be executed between
            // slices (as there is no slicing)
     libdar::crypto_blowfish,
            // the blowfish strong encryption
            // will be used
     "",    // as the password is not given here   
            // (empty string is not a valid password)
            // it will be asked interactively to the
            // user through the dialog
            // user_interaction object
     20480, // the block of encryption will be
            // 20 kbytes
     libdar::not_mask(libdar::simple_mask("*gz")),
            // all files will be compressed except
            // those ending by "gz"
     800,   // file which size is below 800 bytes
            // will not be compressed
     false, // all files will be saved whatever is
            // the nodump flag value
     false, // as we make a full backup this
            // "ignore_owner" parameter is useless
      0,    // hourshift is useless here as we make
            // a full backup
     false, // we will make a real archive not a
            // dry-run operation
     true,  // dar will set back the access time of
            // file it opens, which will change the
            // ctime date of theses files
     false, // we may change of filesystem if
            // necessary
     ret,   // this value is returned by libdar
     exception, // thisgives the status of the call
     except_msg); // and in case of error the cause.

if(exception != LIBDAR_NOEXCEPT)
  std::cout << "an error occured: " << except_msg
            << std::endl;



When creating an archive, the created archive object can be used only as reference for a isolation or for differential backup. You cannot use it for restoration, listing, comparison, because the underlying file descriptors are openned in write only mode. An implementation which uses file descriptors in read-write access is not possible and is not a good idea anyway. Why ? Because, for example, if you want to test your just created archive, using the just created object would make the testing rely on information stored in virtual memory (the archive contents, the data location of a file, etc.), not in the file archive. If some corruption occured in the file you would not notice it.

So to totally complete the archive creation we must destroy the archive object we have just created, which have also as consequence to close any file descriptor used by the object :



     delete my_arch;


libdar::close_archive_noexcept(my_arch, exception,
                        except_msg);

if(exception != LIBDAR_NOEXCEPT)
  std::cout << "an error occured: " << except_msg
            << std::endl;


6 - Testing the archive we have created

So, as explained previously, we must create a new archive object but this time with the "read" constructor:



my_arch = new
libdar::archive(dialog,     
        "/tmp",  // where is the archive
        "my_archive", // slice name
        "dar",   // dar's archive extensions
        libdar::crypto_blowfish,
        "",
        20480, // theses last three are for encryptions
        "",    // not used as we didn't gave "-" as
        "",    // slice name
        "",    // no command executed for now
        false); // no verbose output

my_arch =
libdar::open_archive_noexcept(dialog,     
        "/tmp",  // where is the archive
        "my_archive", // slice name
        "dar",   // dar's archive extensions
        libdar::crypto_blowfish,
        "",
        20480, // theses last three are for encryptions
        "",    // not used as we didn't gave "-" as
        "",    // slice name
        "",    // no command executed for now
        false, // no verbose output
       exception,// this gives the status of the call
       except_msg); // and in case of error the
                    // cause of the error

i
f(exception != LIBDAR_NOEXCEPT)
  std::cout << "an error occured: " << except_msg
            << std::endl;




Now that we have openned the archive we can perform all operation on it, let's thus start by testing the archive coherence:



ret = my_arch->op_test(dialog,
             libdar::bool_mask(true),
                        // all files are tested
             libdar::bool_mask(true),
                        //no directory is prune
             false);    // no verbose output    

 
ret = libdar::op_test_noexcept(
dialog,
       my_arch,         // the archive to test
       libdar::bool_mask(true),
                 // all files are tested
       libdar::bool_mask(true),
                 //no directory is prune
       false,    // no verbose output

       exception,// this gives the status of the call
       except_msg); // and in case of error the
                    // cause of the error

if(exception != LIBDAR_NOEXCEPT)
  std::cout << "an error occured: " << except_msg
            << std::endl;


We have tested the archive, but have not yet seen the libdar::statistics variable. It has been used to create an archive as well as here to test it.  This structure reports the number of files treated, as well as the number files with error and the type of error. You can have a look at the API reference guide for more information about the use of different field. Here is an example, which relies on the class deci to display the value of an infinint variable:

     
     // we need the class deci to display the value of an infinint:
#include "deci.hpp"

 std::cout << std::string("Number of file treated :") << libdar::deci(ret.treated).human() << std::endl;

    // or much more simple (but totally equivalent):
 std::cout << std::string("Number of file treated :") libdar::<< ret.treated << std::endl;


Note that the use of the class deci may throw exceptions (in case of lack of memory, for example), and there is actually no wrapper available to trap the exceptions that may be thrown by the class deci. So you have to protect the code using a try {} catch {}  statment.

7 - listing archive contents

The simple way:


my_arch->op_listing(dialog,
             false, // not a verbose output
             false, // not using the tar-like format
             bool_mask(true),
                    // all filenames are listed
             false);// do not filter unsaved files 

 
libdar::op_test_listing(
dialog,
     
false, // not a verbose output
      false, // not using the tar-like format
      bool_mask(true),
             // all filenames are listed
       false,// do not filter unsaved files

       exception,// this gives the status of the call
       except_msg); // and in case of error the
                    // cause of the error

if(exception != LIBDAR_NOEXCEPT)
  std::cout << "an error occured: " << except_msg
            << endl;


The listing will be done calling the warning() method of the dialog object once for each file to list. This may not be very interesting because you will have just a string for each file, and it would require some parsing if you would like to split the listing in column, or display only filenames first and have other information available to the user in another way. The solution to this problem is to change the user_interaction object.

The user_interaction class has a listing() method which provides as much arguments as different information to display:

In the user_interaction class (a pure virtual class), the listing() method is not a pure virtual method, so you are not obliged to overwrite it, but it has just an empty implemtation so it does nothing. You understand now that, by default, this method is not used. To activate it, you must call  set_use_listing(true) protected method and of course you will have to ovewrite the listing() method to have a less silly behavior:


    // here follows the definition of our own implementation of
    // of a user_interaction class

class my_user_interaction : public user_interaction
{
public :
     // the inherited pure virtual methods we must define
     // as seen at the beginning of this tutorial:
       void pause(const std::string & message);
       void warning(const std::string & message);
       std::string get_string(const std::string & message, bool echo);
       user_interaction *clone() const;

    // we can overwrite this method to have splitted fields for listing:
        void listing(const std::string & flag,
                            const std::string & perm,
                            const std::string & uid,
                            const std::string & gid,
                            const std::string & size,
                            const std::string & date,
                            const std::string & filename,
                            bool is_dir,
                            bool has_children);

     // but it will not get used by libdar unless we call the protected method set_use_listing()
     // for example this can be done in the class constructor :

     my_user_interaction() { set_use_listing(true); };
};


Now assuming we have implemented the listing() method in  my_user_interaction class, calling op_listing() exactly as we did in the simple way, but just replacing the dialog object by one of the my_user_interaction class, would make this listing() method called for each file to be listed, in place of the warning() method.

As seen at the beginning of this tutorial too, there is a children class of user_interaction based on callback functions which is called user_interaction_callback. The listing() method must also be activated here. This is done automatically when you give a callback function to the object, thanks to the set_listing_callback() method :

 
  // our mandatory callback functions:

void warning_callback(const std::string &x, void *context)
{
    ....
}
 
bool answer_callback(const std::string &x, void *context)
{
    ....
}

std::string string_callback(const std::string &x, bool echo, void *context)
{
    ....
}

  // let's build a user_interaction_callback object:

libdar::user_interaction_callback dialog =
        libdar::user_interaction_callback(&warning_callback, &answer_callback, &string_callback, NULL);

   // at this point our dialog object is perfectly operational for listing
   // but libdar will call the warning_callback function to list the archive
   // contents

   // a new callback function for listing :

void listing_callback(const std::string & flag,
                      const std::string & perm,
                      const std::string & uid,
                      const std::string & gid,
                      const std::string & size,
                      const std::string & date,
                      const std::string & filename,
                      bool is_dir,
                      bool has_children,
                      void *context)
{
    ....
}

dialog.set_listing_callback(&listing_callback);

   // now libdar will call the listing_callback function when we
   // will use this dialog object for listing the archive contents.



8 - comparing with filesystem

comparison is realized by calling the op_diff method of the class archive.


     ret = my_arch->op_diff(dialog,
                 "/home", // what directory to take
                          // as root we shall
                          // compare the archive
                          // contents to
                 libdar::bool_mask(true),
                 libdar::bool_mask(true),
                 false,   // no verbose output
                 true,    // comparing root EA
                 true,    // comparing user EA
                 false,   // do not ignore ownership
                          // differences
                 false);  // do not set back atime
                          // of read files





           
  ret =
libdar::op_diff_noexcept(dialog,
                 my_arch, // the archive to use
                 "/home", // what directory to take
                          // as root we shall
                          // compare the archive
                          // contents to
                 libdar::bool_mask(true),
                 libdar::bool_mask(true),
                 false,   // no verbose output
                 true,    // comparing root EA
                 true,    // comparing user EA
                 false,   // do not ignore ownership
                          // differences
                 false,   // do not set back atime
                          // of read    
                 files
exception, // this gives the
                          // status of the call
                 except_msg); // and in case of
                          // error the cause of the
                          // error

if(exception != LIBDAR_NOEXCEPT)
  std::cout << "an error occured: " << except_msg
            << std::endl;


simple, no ?

9 - restoring files

restoration of files is done by calling the  op_extract method of archive class.



ret = my_arch->op_extract(dialog,
             "/tmp",   // where to restore files to
             libdar::bool_mask(true),
                       // restore any filename
            libdar::simple_path_mask("denis/.tcshrc",
                               true),
                            // but only restore
                            // this file or directory
             false,// overwriting not allowed
             true, // warn before overwriting
                   // useless here, not overwritting
             true, // verbose output
             true, // remove files marked as deleted
                   // useless here too, as verwriting
                   // has been disabled
             false,// restore even if a file is more
                   // recent, (useless here too)
             true, // restore root EA  
             true, // restore user EA
             false,// restore directory structure   
             false,// restore ownership
             false,// don't warn if a file to be
                   // removed has a type that does
                   // the type of the orginal file  
             0,   // no daylight saving consideration
             false); // not a dry-run execution

 
ret = libdar::op_extract_noexcept(
dialog,
       my_arch,         // the archive to test
      
"/tmp",   // where to restore files to
       libdar::bool_mask(true),
                // restore any filename
       libdar::simple_path_mask("denis/.tcshrc",
                                true),
                        // but only restore
                        // this file or directory
       false,// overwriting not allowed
       true, // warn before overwriting
             // useless here, not overwritting
       true, // verbose output
       true, // remove files marked as deleted
             // useless here too, as verwriting
             // has been disabled
       false,// restore even if a file is more
             // recent, (useless here too)
       true, // restore root EA  
       true, // restore user EA
       false,// restore directory structure   
       false,// restore ownership
       false,// don't warn if a file to be
             // removed has a type that does
             // the type of the orginal file  
        0,   // no daylight saving consideration
       false,// not a dry-run execution

       exception,// this gives the status of the call
       except_msg); // and in case of error the
                    // cause of the error

if(exception != LIBDAR_NOEXCEPT)
  std::cout << "an error occured: " << except_msg
            << std::endl;


10 - isolating the catalogue

OK, I know, catalogue is not an english word (one would rather write catalog), but that's the name of the C++ class used in libdar, so we will keep using it here. Note that you don't have to directly access to this class.

Isolating the catalogue creates a new archive that only contains the list of files and their attributes (ownership, dates, size, etc.), but no data and no EA are stored in it. It is very similar to the same archive one get if he would made a differential backup of a filesystem that has not changed since the archive of reference. The usage is very similar to the archive creation, but it uses a different constructor that has less arguments :



libdar::archive *my_cat = new libdar::archive(dialog,
                "/tmp",  // where is saved the
                         // extracted catalogue
                my_arch, // the archive of reference
                         // is the one we have been
                         // playing with previously
                "my_catalogue", // slice name
                "dar",   // file extension
                true,    // allow slice overwriting
                true,    // but warn before
                true,    // verbose output
                true,    // pause between slices
                libdar::bzip2, // compression
                9,       // max compression level
                3000, // cut in slices of 3000 Bytes
                3000, // first slice size is the same
                "echo slice %p/%b.%n.%e created",
                      // the script to run after
                      // slice creation
                libdar::crypto_none, // no encryption
                "",    // unused password
                0,     // unused crypto size
                false); // not a dry-run execution
      

           
libdar::archive *my_cat =
    libdar::op_isolate_noexcept(dialog,
               "/tmp",   // where is saved the
                         // extracted catalogue
                my_arch, // the archive of reference
                         // is the one we have been
                         // playing with previously
                "my_catalogue", // slice name
                "dar",   // file extension
                true,    // allow slice overwriting
                true,    // but warn before
                true,    // verbose output
                true,    // pause between slices
                libdar::bzip2, // compression
                9,       // max compression level
                3000, // cut in slices of 3000 Bytes
                3000, // first slice size is the same
                "echo slice %p/%b.%n.%e created",
                      // the script to run after
                      // slice creation
                libdar::crypto_none, // no encryption
                "",    // unused password
                0,     // unused crypto size
                false, // not a dry-run execution

                exception,
                       // this gives the status
                       // of the call
                except_msg);
                       // and in case of error the
                       // cause of the error

if(exception != LIBDAR_NOEXCEPT)
  std::cout << "an error occured: " << except_msg
            << std::endl;



Now we have two archive objects. my_arch is a read-only object created by the "read" constructor. You can do any operations with it, like file restoration, file comparison, archive testing, as we have done in the previous paragraphs. The second archive object is my_cat which is a write only object. It can only be used as reference for another backup (a differential backup) or as a reference for a subsequent catalogue isolation (which would just clone the already isolated catalogue object, here).

Note, that an isolated catalogue can be tested, compared with filesystem, and even you can try to restore files from it. But as there is no data associated with files contents, dar will not restore any file from it, of course. So for now we will just destroy the extracted catalogue object, for all its file descriptors to be closed:



delete my_cat;   


close_archive_noexcept (my_cat, exception,
                        except_msg);

if(exception != LIBDAR_NOEXCEPT)
  std::cout << "an error occured: " << except_msg
            << std::endl;



and we keep the my_arch object for our last operation :

11 - creating a differential backup

This operation is the same as the first one we did (archive creation). You have maybe noted that an argument was set to NULL,  here we will give it the value of my_arch which means that my_arch will become the archive of reference for the archive we will create. If we had not destroyed my_cat above, we could have been using it in place of my_arch for exactly the same result.


 
libdar::archive *my_other_arch =
     new libdar::archive(dialog,
     "/home",  // saving all under this "root"
     "/tmp",   // where the slices will go
     my_arch,  // differential backup
     not_mask(simple_mask("*~", true)),
            // we don't save the files ending with
            // '~' this does not concern directories
     bool_mask(true),
            // all directories and files not rejected
            // by the previous mask are saved
     "my_archive", 
            // the basename of the slices
     "dar", // dar's slice extensions
     true,  // we allow slice overwriting
     true,  // but ask to be warned in such occurence
     false, // we don't want a verbose output
     false, // nor we want to pause between slices
     true,  // rejected directory will be saved as
            // empty (no directory is rejected so
            // here there is no importance for that
            // parameter)
     libdar::gzip // the archive will be compressed
            // using gzip
     9,     // at maximum compression level
     0,     // no slicing is done,
     0,     // so the first slice size must also be
            // set to zero
     true,  // root EA will be saved if present
     true,  // user EA too
     "",    // no script will be executed between
            // slices (as there is no slicing)
     libdar::crypto_blowfish,
            // the blowfish strong encryption
            // will be used
     "",    // as the password is not given here   
            // (empty string is not a valid password)
            // it will be asked interactively to the
            // user through the dialog
            // user_interaction object
     20480, // the block of encryption will be
            // 20 kbytes
     not_mask(simple_mask("*gz")),
            // all files will be compressed except
            // those ending by "gz"
     800,   // file which size is below 800 bytes
            // will not be compressed
     false, // all files will be saved whatever is
            // the nodump flag value
     false, // as we make a full backup this
            // "ignore_owner" parameter is useless
      0,    // hourshift is useless here as we make
            // a full backup
     false, // we will make a real archive not a
            // dry-run operation
     true,  // dar will set back the access time of
            // file it opens, which will change the
            // ctime date of theses files
     false, // we may change of filesystem if
            // necessary
     ret);  // this value is returned by libdar


libdar::archive *my_other_arch =    
     libdar::create_archive_noexcept(dialog,
 
     "/home",  // saving all under this "root"
     "/tmp",   // where the slices will go
     my_arch,  // differential backup
     not_mask(simple_mask("*~", true)),
            // we don't save the files ending with
            // '~' this does not concern directories
     bool_mask(true),
            // all directories and files not rejected
            // by the previous mask are saved
     "my_archive", 
            // the basename of the slices
     "dar", // dar's slice extensions
     true,  // we allow slice overwriting
     true,  // but ask to be warned in such occurence
     false, // we don't want a verbose output
     false, // nor we want to pause between slices
     true,  // rejected directory will be saved as
            // empty (no directory is rejected so
            // here there is no importance for that
            // parameter)
     libdar::gzip // the archive will be compressed
            // using gzip
     9,     // at maximum compression level
     0,     // no slicing is done,
     0,     // so the first slice size must also be
            // set to zero
     true,  // root EA will be saved if present
     true,  // user EA too
     "",    // no script will be executed between
            // slices (as there is no slicing)
     libdar::crypto_blowfish,
            // the blowfish strong encryption
            // will be used
     "",    // as the password is not given here   
            // (empty string is not a valid password)
            // it will be asked interactively to the
            // user through the dialog
            // user_interaction object
     20480, // the block of encryption will be
            // 20 kbytes
     not_mask(simple_mask("*gz")),
            // all files will be compressed except
            // those ending by "gz"
     800,   // file which size is below 800 bytes
            // will not be compressed
     false, // all files will be saved whatever is
            // the nodump flag value
     false, // as we make a full backup this
            // "ignore_owner" parameter is useless
      0,    // hourshift is useless here as we make
            // a full backup
     false, // we will make a real archive not a
            // dry-run operation
     true,  // dar will set back the access time of
            // file it opens, which will change the
            // ctime date of theses files
     false, // we may change of filesystem if
            // necessary
     ret,   // this value is returned by libdar
     exception, // thisgives the status of the call
     except_msg); // and in case of error the cause.

if(exception != LIBDAR_NOEXCEPT)
  std::cout << "an error occured: " << except_msg
            << std::endl;


As previously my_other_arch is a write only object that we won't need anymore. So we destroy it:


     delete my_other_arch;


libdar::close_archive_noexcept(my_other_arch,
                        exception,
                        except_msg);

if(exception != LIBDAR_NOEXCEPT)
  std::cout << "an error occured: " << except_msg
            << std::endl;




So, we are at the end of the tutorial, but still remains an object we need to destroy to cleanly release the memory used :



     delete my_arch;


libdar::close_archive_noexcept(my_arch, exception,
                        except_msg);

if(exception != LIBDAR_NOEXCEPT)
  std::cout << "an error occured: " << except_msg
            << std::endl;



For more detailed information about the API you have the API reference guide, built from source code by Doxygen.