LCOV - code coverage report
Current view: top level - client - client.c (source / functions) Hit Total Coverage
Test: coverage-client.info Lines: 441 477 92.5 %
Date: 2016-02-03 22:31:46 Functions: 23 23 100.0 %

          Line data    Source code
       1             : /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
       2             : /*
       3             :  *    client.c
       4             :  *    This file is part of "Sauvegarde" project.
       5             :  *
       6             :  *    (C) Copyright 2014 - 2016 Olivier Delhomme
       7             :  *     e-mail : olivier.delhomme@free.fr
       8             :  *
       9             :  *    "Sauvegarde" is free software: you can redistribute it and/or modify
      10             :  *    it under the terms of the GNU General Public License as published by
      11             :  *    the Free Software Foundation, either version 3 of the License, or
      12             :  *    (at your option) any later version.
      13             :  *
      14             :  *    "Sauvegarde" is distributed in the hope that it will be useful,
      15             :  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :  *    GNU General Public License for more details.
      18             :  *
      19             :  *    You should have received a copy of the GNU General Public License
      20             :  *    along with "Sauvegarde".  If not, see <http://www.gnu.org/licenses/>
      21             :  */
      22             : 
      23             : /**
      24             :  * @file client.c
      25             :  *
      26             :  * This file is the main file for the client program. This program has
      27             :  * to monitor file changes onto filesystems. It should notice
      28             :  * when a file is created, deleted or changed
      29             :  */
      30             : 
      31             : #include "client.h"
      32             : 
      33             : static GSList *make_regex_exclude_list(GSList *exclude_list);
      34             : static gboolean exclude_file(GSList *regex_exclude_list, gchar *filename);
      35             : static main_struct_t *init_main_structure(options_t *opt);
      36             : static GList *calculate_hash_data_list_for_file(GFile *a_file, gint64 blocksize);
      37             : static meta_data_t *get_meta_data_from_fileinfo(file_event_t *file_event, filter_file_t *filter, options_t *opt);
      38             : static gchar *send_meta_data_to_server(main_struct_t *main_struct, meta_data_t *meta, gboolean data_sent);
      39             : static GList *find_hash_in_list(GList *hash_data_list, guint8 *hash);
      40             : static void send_data_to_server(main_struct_t *main_struct, meta_data_t *meta, gchar *answer);
      41             : static void send_all_data_to_server(main_struct_t *main_struct, meta_data_t *meta, gchar *answer);
      42             : static void iterate_over_enum(main_struct_t *main_struct, gchar *directory, GFileEnumerator *file_enum);
      43             : static void carve_one_directory(gpointer data, gpointer user_data);
      44             : static gpointer carve_all_directories(gpointer data);
      45             : static gpointer save_one_file_threaded(gpointer data);
      46             : static gpointer free_file_event_t(file_event_t *file_event);
      47             : static gint insert_array_in_root_and_send(main_struct_t *main_struct, json_t *array);
      48             : static void process_small_file_not_in_cache(main_struct_t *main_struct, meta_data_t *meta);
      49             : static gint64 calculate_file_blocksize(options_t *opt, gint64 size);
      50             : static gpointer reconnected(gpointer data);
      51             : 
      52             : /**
      53             :  * Make a list of precompiled GRegex to be used to filter out directories
      54             :  * and filenames from being saved.
      55             :  * @param exclude_list is the list of gchar * string that should contain
      56             :  *        filenames and/or dirnames with basic regex notation.
      57             :  * @returns A newly allocated list of compiled GRegex * pointers.
      58             :  */
      59           1 : static GSList *make_regex_exclude_list(GSList *exclude_list)
      60             : {
      61           1 :     GRegex *a_regex = NULL;
      62           1 :     GError *error = NULL;
      63           1 :     GSList *regex_exclude_list = NULL;
      64             : 
      65           6 :     while (exclude_list != NULL)
      66             :         {
      67           4 :             a_regex = g_regex_new(exclude_list->data, G_REGEX_CASELESS, 0, &error);
      68             : 
      69           4 :             if (error != NULL)
      70             :                 {
      71           0 :                     print_error(__FILE__, __LINE__, _("Error while compiling %s to a regular expression: %s"), exclude_list->data, error->message);
      72             :                 }
      73           4 :             else if (a_regex != NULL)
      74             :                 {
      75           4 :                     regex_exclude_list = g_slist_prepend(regex_exclude_list, a_regex);
      76             :                 }
      77             : 
      78           4 :             exclude_list = g_slist_next(exclude_list);
      79             :         }
      80             : 
      81           1 :     return regex_exclude_list;
      82             : }
      83             : 
      84             : 
      85             : /**
      86             :  * Says if 'filename' may correspond to one of the regex of the list.
      87             :  * @param regex_exclude_list is the list of precompiled Regex of files
      88             :  *        to be excluded from being saved.
      89             :  * @param filename is the name pf the file that we want to know if we
      90             :  *        have to exclude it or not.
      91             :  * @returns TRUE if the file has to be excluded, FALSE otherwise
      92             :  */
      93       51772 : static gboolean exclude_file(GSList *regex_exclude_list, gchar *filename)
      94             : {
      95       51772 :     gboolean result = FALSE;
      96             : 
      97      304603 :     while (regex_exclude_list != NULL && result == FALSE)
      98             :         {
      99      201059 :             result = g_regex_match(regex_exclude_list->data, filename, 0, NULL);
     100      201059 :             regex_exclude_list = g_slist_next(regex_exclude_list);
     101             :         }
     102             : 
     103       51772 :     return result;
     104             : }
     105             : 
     106             : 
     107             : /**
     108             :  * Inits the main structure.
     109             :  * @note With sqlite version > 3.7.7 we should use URI filename.
     110             :  * @param opt : a filled options_t * structure that contains all options
     111             :  *        by default, read into the file or selected in the command line.
     112             :  * @returns a main_struct_t * pointer to the main structure
     113             :  */
     114           1 : static main_struct_t *init_main_structure(options_t *opt)
     115             : {
     116           1 :     main_struct_t *main_struct = NULL;
     117           1 :     gchar *db_uri = NULL;
     118           1 :     gchar *conn = NULL;
     119             : 
     120           1 :     if (opt != NULL)
     121             :         {
     122             : 
     123           1 :             print_debug(_("Please wait while initializing main structure...\n"));
     124             : 
     125           1 :             main_struct = (main_struct_t *) g_malloc0(sizeof(main_struct_t));
     126             : 
     127           1 :             create_directory(opt->dircache);
     128           1 :             db_uri = g_build_filename(opt->dircache, opt->dbname , NULL);
     129           1 :             main_struct->database = open_database(db_uri);
     130           1 :             db_uri = free_variable(db_uri);
     131             : 
     132           1 :             main_struct->opt = opt;
     133           1 :             main_struct->hostname = g_get_host_name();
     134             : 
     135           1 :             if (opt != NULL && opt->ip != NULL)
     136             :                 {
     137           1 :                     conn = make_connexion_string(opt->ip, opt->port);
     138           1 :                     main_struct->comm = init_comm_struct(conn);
     139           1 :                     main_struct->reconnected = init_comm_struct(conn);
     140           1 :                     free_variable(conn);
     141             :                 }
     142             :             else
     143             :                 {
     144             :                     /* This should never happen because we have default values */
     145           0 :                     main_struct->comm = NULL;
     146             :                 }
     147             : 
     148           1 :             main_struct->signal_fd = start_signals();
     149           1 :             main_struct->fanotify_fd = start_fanotify(opt);
     150             : 
     151             :             /* inits the queue that will wait for events on files */
     152           1 :             main_struct->save_queue = g_async_queue_new();
     153           1 :             main_struct->dir_queue = g_async_queue_new();
     154           1 :             main_struct->regex_exclude_list = make_regex_exclude_list(opt->exclude_list);
     155             : 
     156             :             /* Thread initialization */
     157           1 :             main_struct->save_one_file = g_thread_new("save_one_file", save_one_file_threaded, main_struct);
     158           1 :             main_struct->carve_all_directories = g_thread_new("carve_all_directories", carve_all_directories, main_struct);
     159           1 :             main_struct->reconn_thread = g_thread_new("reconnected", reconnected, main_struct);
     160             : 
     161           1 :             print_debug(_("Main structure initialized !\n"));
     162             : 
     163             :         }
     164             : 
     165           1 :     return main_struct;
     166             : }
     167             : 
     168             : 
     169             : /**
     170             :  * Calculates hashs for each block of blocksize bytes long on the file
     171             :  * and returns a list of all hashs in correct order stored in a binary
     172             :  * form to save space.
     173             :  * @note This technique has some limits in term of memory footprint
     174             :  *       because one file is entirely in memory at a time. Saving huge
     175             :  *       files may not be possible with this, depending on the size of
     176             :  *       the file and the size of the memory.
     177             :  * @todo Imagine a new way to checksum huge files because of limitations.
     178             :  *       May be with the local sqlite database ?
     179             :  * @param a_file is the file from which we want the hashs.
     180             :  * @param blocksize is the blocksize to be used to calculate hashs upon.
     181             :  * @returns a GSList * list of hashs stored in a binary form.
     182             :  */
     183       48779 : static GList *calculate_hash_data_list_for_file(GFile *a_file, gint64 blocksize)
     184             : {
     185       48779 :     GFileInputStream *stream = NULL;
     186       48779 :     GError *error = NULL;
     187       48779 :     GList *hash_data_list = NULL;
     188       48779 :     hash_data_t *hash_data = NULL;
     189       48779 :     gssize read = 0;
     190       48779 :     guchar *buffer = NULL;
     191       48779 :     GChecksum *checksum = NULL;
     192       48779 :     guint8 *a_hash = NULL;
     193       48779 :     gsize digest_len = HASH_LEN;
     194             : 
     195       48779 :     if (a_file != NULL)
     196             :         {
     197       48779 :             stream = g_file_read(a_file, NULL, &error);
     198             : 
     199       48779 :             if (stream != NULL && error == NULL)
     200             :                 {
     201             : 
     202       48779 :                     checksum = g_checksum_new(G_CHECKSUM_SHA256);
     203       48779 :                     buffer = (guchar *) g_malloc(blocksize);
     204       48779 :                     a_hash = (guint8 *) g_malloc(digest_len);
     205             : 
     206       48779 :                     read = g_input_stream_read((GInputStream *) stream, buffer, blocksize, NULL, &error);
     207             : 
     208      622787 :                     while (read != 0 && error == NULL)
     209             :                         {
     210      525229 :                             g_checksum_update(checksum, buffer, read);
     211      525229 :                             g_checksum_get_digest(checksum, a_hash, &digest_len);
     212             : 
     213             :                             /* Need to save data and read in hash_data_t structure */
     214      525229 :                             hash_data = new_hash_data_t(buffer, read, a_hash);
     215             : 
     216      525229 :                             hash_data_list = g_list_prepend(hash_data_list, hash_data);
     217      525229 :                             g_checksum_reset(checksum);
     218      525229 :                             digest_len = HASH_LEN;
     219             : 
     220      525229 :                             buffer = (guchar *) g_malloc(blocksize);
     221      525229 :                             a_hash = (guint8 *) g_malloc(digest_len);
     222             : 
     223      525229 :                             read = g_input_stream_read((GInputStream *) stream, buffer, blocksize, NULL, &error);
     224             :                         }
     225             : 
     226       48779 :                     if (error != NULL)
     227             :                         {
     228          10 :                             print_error(__FILE__, __LINE__, _("Error while reading file: %s\n"), error->message);
     229          10 :                             error = free_error(error);
     230          10 :                             g_list_free_full(hash_data_list, free_hdt_struct);
     231          10 :                             hash_data_list =  NULL;
     232             :                         }
     233             :                     else
     234             :                         {
     235             :                             /* get the list in correct order (because we prepended the hashs to get speed when inserting hashs in the list) */
     236       48769 :                             hash_data_list = g_list_reverse(hash_data_list);
     237             :                         }
     238             : 
     239       48779 :                     free_variable(buffer);
     240       48779 :                     free_variable(a_hash);
     241             : 
     242       48779 :                     g_checksum_free(checksum);
     243       48779 :                     g_input_stream_close((GInputStream *) stream, NULL, NULL);
     244       48779 :                     free_object(stream);
     245             :                 }
     246             :             else
     247             :                 {
     248           0 :                     print_error(__FILE__, __LINE__, _("Unable to open file for reading: %s\n"), error->message);
     249           0 :                     error = free_error(error);
     250             :                 }
     251             :         }
     252             : 
     253       48779 :     return hash_data_list;
     254             : }
     255             : 
     256             : 
     257             : /**
     258             :  * Gets the attributes of a file
     259             :  * @param meta is the structure where to store meta data (attributes) of
     260             :  *        the file
     261             :  * @param fileinfo is a glib structure that contains a lot of informations
     262             :  *        about the file and from which we want to keep a few.
     263             :  */
     264       49745 : static void get_file_attributes(meta_data_t *meta, GFileInfo *fileinfo)
     265             : {
     266       49745 :     if (meta != NULL)
     267             :         {
     268       49745 :             meta->inode = g_file_info_get_attribute_uint64(fileinfo, G_FILE_ATTRIBUTE_UNIX_INODE);
     269       49745 :             meta->owner = g_file_info_get_attribute_as_string(fileinfo, G_FILE_ATTRIBUTE_OWNER_USER);
     270       49745 :             meta->group = g_file_info_get_attribute_as_string(fileinfo, G_FILE_ATTRIBUTE_OWNER_GROUP);
     271       49745 :             meta->uid = g_file_info_get_attribute_uint32(fileinfo, G_FILE_ATTRIBUTE_UNIX_UID);
     272       49745 :             meta->gid = g_file_info_get_attribute_uint32(fileinfo, G_FILE_ATTRIBUTE_UNIX_GID);
     273       49745 :             meta->atime = g_file_info_get_attribute_uint64(fileinfo, G_FILE_ATTRIBUTE_TIME_ACCESS);
     274       49745 :             meta->ctime = g_file_info_get_attribute_uint64(fileinfo, G_FILE_ATTRIBUTE_TIME_CHANGED);
     275       49745 :             meta->mtime = g_file_info_get_attribute_uint64(fileinfo, G_FILE_ATTRIBUTE_TIME_MODIFIED);
     276       49745 :             meta->mode = g_file_info_get_attribute_uint32(fileinfo, G_FILE_ATTRIBUTE_UNIX_MODE);
     277       49745 :             meta->size = g_file_info_get_attribute_uint64(fileinfo, G_FILE_ATTRIBUTE_STANDARD_SIZE);
     278             : 
     279             :              /* Do the right things with specific cases */
     280       49745 :             if (meta->file_type == G_FILE_TYPE_SYMBOLIC_LINK)
     281             :                 {
     282         634 :                     meta->link = (gchar *) g_file_info_get_attribute_byte_string(fileinfo, G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET);
     283             :                 }
     284             :             else
     285             :                 {
     286       49111 :                     meta->link = g_strdup("");
     287             :                 }
     288             :         }
     289       49745 : }
     290             : 
     291             : 
     292             : /**
     293             :  * Gets all meta data for a file and returns a filled meta_data_t *
     294             :  * structure.
     295             :  * @param file_event is the structure that contains directory and fileinfo
     296             :  *        structures. directory is the directory we are iterating over. It
     297             :  *        is used here to build the filename name. fileinfo is a glib
     298             :  *        structure that contains all meta data and more for a file.
     299             :  * @param filter is a structure containing all structures needed to filter
     300             :  *        files as database, regex_exclude_list and contains a boolean
     301             :  *        that is set to TRUE if the file has been filtered out and FALSE
     302             :  *        otherwise.
     303             :  * @param opt are the selected options for the program.
     304             :  * @returns a newly allocated and filled meta_data_t * structure.
     305             :  */
     306       51772 : static meta_data_t *get_meta_data_from_fileinfo(file_event_t *file_event, filter_file_t *filter, options_t *opt)
     307             : {
     308       51772 :     meta_data_t *meta = NULL;
     309       51772 :     gchar *directory = NULL;
     310       51772 :     GFileInfo *fileinfo = NULL;
     311             : 
     312       51772 :     if (file_event != NULL)
     313             :         {
     314       51772 :             directory = file_event->directory;
     315       51772 :             fileinfo = file_event->fileinfo;
     316             :         }
     317             : 
     318       51772 :     if (directory != NULL && fileinfo != NULL &&  filter != NULL && filter->database != NULL)
     319             :         {
     320             :             /* filling meta data for the file represented by fileinfo */
     321       51772 :             meta = new_meta_data_t();
     322             : 
     323       51772 :             meta->file_type = g_file_info_get_file_type(fileinfo);
     324       51772 :             meta->name = g_build_path(G_DIR_SEPARATOR_S, directory, g_file_info_get_name(fileinfo), NULL);
     325             : 
     326       51772 :             if (exclude_file(filter->regex_exclude_list, meta->name) == FALSE)
     327             :                 {
     328             :                     /* fills meta_data_t *meta structure */
     329       49745 :                     get_file_attributes(meta, fileinfo);
     330       49745 :                     meta->blocksize = calculate_file_blocksize(opt, meta->size);
     331             : 
     332             :                     /* We need to determine if the file has already been saved by looking into the local database
     333             :                      * This is usefull only when carving directories at the begining of the process as when called
     334             :                      * by m_fanotify we already know that the file was written and that something changed.
     335             :                      */
     336       49745 :                     meta->in_cache = is_file_in_cache(filter->database, meta);
     337       49745 :                     filter->excluded = FALSE;
     338             :                 }
     339             :             else
     340             :                 {
     341        2027 :                     filter->excluded = TRUE;
     342             :                 }
     343             :         }
     344             : 
     345       51772 :     return meta;
     346             : }
     347             : 
     348             : 
     349             : /**
     350             :  * Sends meta data to the server and returns it's answer or NULL in
     351             :  * case of an error.
     352             :  * @param main_struct : main structure of the program (contains pointers
     353             :  *        to the communication socket.
     354             :  * @param meta : the meta_data_t * structure to be saved.
     355             :  * @returns a newly allocated gchar * string that may be freed when no
     356             :  *          longer needed.
     357             :  */
     358       49745 : static gchar *send_meta_data_to_server(main_struct_t *main_struct, meta_data_t *meta, gboolean data_sent)
     359             : {
     360       49745 :     gchar *json_str = NULL;
     361       49745 :     gchar *answer = NULL;
     362       49745 :     gint success = CURLE_FAILED_INIT;
     363       49745 :     json_t *root = NULL;
     364       49745 :     json_t *array = NULL;
     365             : 
     366       49745 :     if (main_struct != NULL && meta != NULL && main_struct->hostname != NULL)
     367             :         {
     368       49745 :             json_str = convert_meta_data_to_json_string(meta, main_struct->hostname, data_sent);
     369             : 
     370             :             /* Sends meta data here: readbuffer is the buffer sent to server */
     371       49745 :             print_debug(_("Sending meta data: %s\n"), json_str);
     372       49745 :             main_struct->comm->readbuffer = json_str;
     373       49745 :             success = post_url(main_struct->comm, "/Meta.json");
     374             : 
     375       49745 :             if (success == CURLE_OK)
     376             :                 {
     377       49745 :                     answer = g_strdup(main_struct->comm->buffer);
     378       49745 :                     main_struct->comm->buffer = free_variable(main_struct->comm->buffer);
     379             :                 }
     380             :             else
     381             :                 {
     382             :                     /* Need to manage HTTP errors ? */
     383             :                     /* Saving meta data that should have been sent to sqlite database */
     384           0 :                     db_save_buffer(main_struct->database, "/Meta.json", main_struct->comm->readbuffer);
     385             : 
     386             :                     /* An error occured -> we need the whole hash list to be saved
     387             :                      * we are building a 'fake' answer with the whole hash list.
     388             :                      */
     389           0 :                     array = convert_hash_list_to_json(meta->hash_data_list);
     390           0 :                     root = json_object();
     391           0 :                     insert_json_value_into_json_root(root, "hash_list", array);
     392           0 :                     answer = json_dumps(root, 0);
     393           0 :                     json_decref(root);
     394             :                 }
     395             : 
     396       49745 :             free_variable(main_struct->comm->readbuffer);
     397             :         }
     398             : 
     399       49745 :     return answer;
     400             : }
     401             : 
     402             : 
     403             : /**
     404             :  * Finds a hash in the hash data list and returns the hash_data_t that
     405             :  * corresponds to it. In normal operations it should always find
     406             :  * something.
     407             :  * @param hash_data_list is the list to look into for the hash 'hash'
     408             :  * @param hash is the hash to look for.
     409             :  * @returns the GList * pointer that contains hash_data_t structure that
     410             :  *          corresponds to the hash 'hash'.
     411             :  */
     412      223915 : static GList *find_hash_in_list(GList *hash_data_list, guint8 *hash)
     413             : {
     414      223915 :     GList *iter = hash_data_list;
     415      223915 :     hash_data_t *found = NULL;
     416      223915 :     gboolean ok = FALSE;
     417             : 
     418      858875 :     while (iter != NULL && ok == FALSE)
     419             :         {
     420      411045 :             found = iter->data;
     421             : 
     422      411045 :             if (compare_two_hashs(hash, found->hash) == 0)
     423             :                 {
     424             :                     ok = TRUE;
     425             :                 }
     426             :             else
     427             :                 {
     428      187130 :                    iter = g_list_next(iter);
     429             :                 }
     430             :         }
     431             : 
     432      223915 :     if (ok == TRUE)
     433             :         {
     434      223915 :             return iter;
     435             :         }
     436             :     else
     437             :         {
     438             :             return NULL;
     439             :         }
     440             : }
     441             : 
     442             : 
     443             : /**
     444             :  * Inserts the array into a root json_t * structure and dumps it into a
     445             :  * buffer that is send to the server and then freed.
     446             :  * @param main_struct : main structure of the program.
     447             :  * @param array is the json_t * array to be sent to the server
     448             :  */
     449       44123 : static gint insert_array_in_root_and_send(main_struct_t *main_struct, json_t *array)
     450             : {
     451       44123 :     json_t *root = NULL;
     452       44123 :     gint success = CURLE_FAILED_INIT;
     453             : 
     454             : 
     455       44123 :     if (main_struct != NULL && main_struct->comm != NULL && array != NULL)
     456             :         {
     457             : 
     458       44123 :             root = json_object();
     459       44123 :             insert_json_value_into_json_root(root, "data_array", array);
     460             : 
     461             :             /* readbuffer is the buffer sent to server */
     462       44123 :             main_struct->comm->readbuffer = json_dumps(root, 0);
     463             : 
     464       44123 :             success = post_url(main_struct->comm, "/Data_Array.json");
     465             : 
     466       44123 :             if (success != CURLE_OK)
     467             :                 {
     468           0 :                     db_save_buffer(main_struct->database, "/Data_Array.json", main_struct->comm->readbuffer);
     469             :                 }
     470             : 
     471       44123 :             free_variable(main_struct->comm->readbuffer);
     472       44123 :             json_decref(root);
     473       44123 :             main_struct->comm->buffer = free_variable(main_struct->comm->buffer);
     474             : 
     475             :         }
     476             : 
     477       44123 :     return success;
     478             : }
     479             : 
     480             : 
     481             : /**
     482             :  * Sends data as requested by the server 'cdpfglserver' in a buffered way.
     483             :  * @param main_struct : main structure of the program.
     484             :  * @param meta : meta is a pointer to meta_data_t strcuture that contains
     485             :  *               hash_data_list the list of hash_data_t * pointers
     486             :  *               containing all all the data to be saved.
     487             :  * @param answer is the request sent back by server when we had send
     488             :  *        meta data.
     489             :  * @note using directly main_struct->comm->buffer -> not threadable as is.
     490             :  */
     491       45022 : static void send_all_data_to_server(main_struct_t *main_struct, meta_data_t *meta, gchar *answer)
     492             : {
     493       45022 :     json_t *root = NULL;
     494       45022 :     json_t *array = NULL;
     495       45022 :     GList *hash_list = NULL;      /** hash_list is local to this function and contains the needed hashs as answer by server */
     496       45022 :     GList *head = NULL;
     497       45022 :     GList *iter = NULL;
     498       45022 :     hash_data_t *found = NULL;
     499       45022 :     hash_data_t *hash_data = NULL;
     500       45022 :     gint bytes = 0;
     501       45022 :     json_t *to_insert = NULL;
     502       45022 :     gint64 limit = 0;
     503       45022 :     a_clock_t *elapsed = NULL;
     504             : 
     505       45022 :     if (answer != NULL && meta != NULL && meta->hash_data_list != NULL && main_struct != NULL && main_struct->opt != NULL)
     506             :         {
     507       44683 :             root = load_json(answer);
     508             : 
     509       44683 :             limit = main_struct->opt->buffersize;
     510             : 
     511       44683 :             if (root != NULL)
     512             :                 {
     513             :                     /* This hash_list is the needed hashs from server */
     514       44683 :                     hash_list = extract_glist_from_array(root, "hash_list", TRUE);
     515       44683 :                     json_decref(root);
     516             : 
     517       44683 :                     array = json_array();
     518             : 
     519       44683 :                     head = hash_list;
     520             : 
     521      310264 :                     while (hash_list != NULL)
     522             :                         {
     523      220898 :                             hash_data = hash_list->data;
     524             :                             /* hash_data_list contains all hashs and their associated data for the file
     525             :                              * being processed */
     526      220898 :                             iter = find_hash_in_list(meta->hash_data_list, hash_data->hash);
     527      220898 :                             found = iter->data;
     528             : 
     529      220898 :                             to_insert = convert_hash_data_t_to_json(found);
     530      220898 :                             json_array_append_new(array, to_insert);
     531             : 
     532      220898 :                             bytes = bytes + found->read;
     533             : 
     534      220898 :                             meta->hash_data_list = g_list_remove_link(meta->hash_data_list, iter);
     535      220898 :                             g_list_free_full(iter, free_hdt_struct);
     536             : 
     537      220898 :                             if (bytes >= limit)
     538             :                                 {
     539             :                                     /* when we've got opt->buffersize bytes of data send them ! */
     540             : 
     541         175 :                                     elapsed = new_clock_t();
     542         175 :                                     insert_array_in_root_and_send(main_struct, array);
     543         175 :                                     array = json_array();
     544         175 :                                     bytes = 0;
     545         175 :                                     end_clock(elapsed, "insert_array_in_root_and_send");
     546             :                                 }
     547             : 
     548      220898 :                             hash_list = g_list_next(hash_list);
     549             :                         }
     550             : 
     551       44683 :                     if (bytes > 0)
     552             :                         {
     553             :                             /* Send the rest of the data (less than opt->buffersize bytes) */
     554       43618 :                             elapsed = new_clock_t();
     555       43618 :                             insert_array_in_root_and_send(main_struct, array);
     556       43618 :                             end_clock(elapsed, "insert_array_in_root_and_send");
     557             :                         }
     558             :                     else
     559             :                         {
     560        1065 :                             json_decref(array);
     561             :                         }
     562             : 
     563       44683 :                     if (head != NULL)
     564             :                         {
     565       43618 :                             g_list_free_full(head, free_hdt_struct);
     566             :                         }
     567             :                 }
     568             :             else
     569             :                 {
     570           0 :                     print_error(__FILE__, __LINE__, _("Error while loading JSON answer from server\n"));
     571             :                 }
     572             :         }
     573       45022 : }
     574             : 
     575             : 
     576             : /**
     577             :  * Sends data as requested by the server 'cdpfglserver'.
     578             :  * @param main_struct : main structure of the program.
     579             :  * @param hash_data_list : list of hash_data_t * pointers containing
     580             :  *                          all the data to be saved.
     581             :  * @param answer is the request sent back by server when we had send
     582             :  *        meta data.
     583             :  * @note using directly main_struct->comm->buffer -> not threadable as is.
     584             :  */
     585        4720 : static void send_data_to_server(main_struct_t *main_struct, meta_data_t *meta, gchar *answer)
     586             : {
     587        4720 :     json_t *root = NULL;
     588        4720 :     GList *hash_list = NULL;         /** hash_list is local to this function */
     589        4720 :     GList *head = NULL;
     590        4720 :     gint success = CURLE_FAILED_INIT;
     591        4720 :     GList *iter = NULL;
     592        4720 :     hash_data_t *found = NULL;
     593        4720 :     hash_data_t *hash_data = NULL;
     594             : 
     595        4720 :     if (main_struct != NULL && main_struct->comm != NULL && answer != NULL &&  meta != NULL && meta->hash_data_list!= NULL)
     596             :         {
     597        4077 :             root = load_json(answer);
     598             : 
     599        4077 :             if (root != NULL)
     600             :                 {
     601             :                     /* This hash_list is the needed hashs from server */
     602        4077 :                     hash_list = extract_glist_from_array(root, "hash_list", TRUE);
     603        4077 :                     json_decref(root);
     604        4077 :                     head = hash_list;
     605             : 
     606       11171 :                     while (hash_list != NULL)
     607             :                         {
     608        3017 :                             hash_data = hash_list->data;
     609             :                             /* hash_data_list contains all hashs and their associated data */
     610        3017 :                             iter = find_hash_in_list(meta->hash_data_list, hash_data->hash);
     611        3017 :                             found = iter->data;
     612             : 
     613             :                             /* readbuffer is the buffer sent to server  */
     614        3017 :                             main_struct->comm->readbuffer = convert_hash_data_t_to_string(found);
     615        3017 :                             success = post_url(main_struct->comm, "/Data.json");
     616             : 
     617        3017 :                             if (success != CURLE_OK)
     618             :                                 {
     619           0 :                                     db_save_buffer(main_struct->database, "/Data.json", main_struct->comm->readbuffer);
     620             :                                 }
     621             : 
     622        3017 :                             free_variable(main_struct->comm->readbuffer);
     623             : 
     624        3017 :                             meta->hash_data_list = g_list_remove_link(meta->hash_data_list, iter);
     625        3017 :                             g_list_free_full(iter, free_hdt_struct);
     626             : 
     627        3017 :                             main_struct->comm->buffer = free_variable(main_struct->comm->buffer);
     628        3017 :                             hash_list = g_list_next(hash_list);
     629             :                         }
     630             : 
     631        4077 :                     if (head != NULL)
     632             :                         {
     633        3017 :                             g_list_free_full(head, free_hdt_struct);
     634             :                         }
     635             :                 }
     636             :             else
     637             :                 {
     638           0 :                     print_error(__FILE__, __LINE__, _("Error while loading JSON answer from server\n"));
     639             :                 }
     640             :         }
     641        4720 : }
     642             : 
     643             : 
     644             : /**
     645             :  * @returns a newly allocated file_event_t * structure that must be freed
     646             :  *          with free_file_event_t() when no longer needed
     647             :  * @param directory is the directory where the event occured
     648             :  * @param fileinfo is fileinfo of the file on which the event occured
     649             :  */
     650       51772 : file_event_t *new_file_event_t(gchar *directory, GFileInfo *fileinfo)
     651             : {
     652       51772 :     file_event_t *file_event = NULL;
     653             : 
     654             : 
     655       51772 :     file_event = (file_event_t *) g_malloc(sizeof(file_event_t));
     656             : 
     657       51772 :     file_event->directory = g_strdup(directory);
     658       51772 :     file_event->fileinfo = g_file_info_dup(fileinfo);
     659             : 
     660       51772 :     return file_event;
     661             : }
     662             : 
     663             : 
     664             : /**
     665             :  * Frees file_event_t's memory
     666             :  * @param file_event is the event to be freed
     667             :  * @returns NULL
     668             :  */
     669       51772 : static gpointer free_file_event_t(file_event_t *file_event)
     670             : {
     671       51772 :     if (file_event != NULL)
     672             :         {
     673       51772 :             free_variable(file_event->directory);
     674       51772 :             free_object(file_event->fileinfo);
     675       51772 :             free_variable(file_event);
     676             :         }
     677             : 
     678       51772 :     return NULL;
     679             : }
     680             : 
     681             : 
     682             : /**
     683             :  * @returns a newly allocated filter_file_t * structure that must be freed
     684             :  *          with free_filter_t() when no longer needed.
     685             :  * @param database is a pointer to the database.
     686             :  * @param regex_exclude_list is the list of regular expressions used to
     687             :  *        filter our files
     688             :  * @param excluded is a gboolean that is used to say whether a file has
     689             :  *        been excluded or not.
     690             :  */
     691             : static filter_file_t *new_filter_t(db_t *database, GSList *regex_exclude_list, gboolean excluded)
     692             : {
     693       51772 :     filter_file_t *filter = NULL;
     694             : 
     695             : 
     696       51772 :     filter = (filter_file_t *) g_malloc(sizeof(filter_file_t));
     697             : 
     698       51772 :     filter->database = database;
     699       51772 :     filter->regex_exclude_list = regex_exclude_list;
     700       51772 :     filter->excluded = excluded;
     701             : 
     702             :     return filter;
     703             : }
     704             : 
     705             : 
     706             : /**
     707             :  * frees filter_file_t *filter's memory
     708             :  * @param filter the filter to be freed
     709             :  * @returns NULL
     710             :  */
     711             : static gpointer free_filter_file_t(filter_file_t *filter)
     712             : {
     713             :     /* Beware not to free database and regex_exclude_list that are
     714             :      * used elsewhere in the program
     715             :      */
     716       51772 :     if (filter != NULL)
     717             :         {
     718       51772 :             g_free(filter);
     719             :         }
     720             :     return NULL;
     721             : }
     722             : 
     723             : 
     724             : /**
     725             :  * Threaded function that saves one file by getting it's meta-data and
     726             :  * it's data and sends them to the server in order to be saved.
     727             :  * @param data must be main_struct_t * pointer.
     728             :  */
     729           1 : static gpointer save_one_file_threaded(gpointer data)
     730             : {
     731           1 :     main_struct_t *main_struct = (main_struct_t *) data;
     732           1 :     file_event_t *file_event = NULL;
     733             : 
     734           1 :     if (main_struct != NULL && main_struct->save_queue != NULL)
     735             :         {
     736             :             while (1)
     737             :                 {
     738       51773 :                     file_event = g_async_queue_pop(main_struct->save_queue);
     739       51772 :                     save_one_file(main_struct, file_event);
     740       51772 :                     free_file_event_t(file_event);
     741       51772 :                 }
     742             :         }
     743             : 
     744           0 :     return NULL;
     745             : }
     746             : 
     747             : 
     748             : /**
     749             :  * Calculates the block size to be used upon a file
     750             :  * @param opt are the selected options for the program.
     751             :  * @param size is the size of the considered file.
     752             :  */
     753       49745 : static gint64 calculate_file_blocksize(options_t *opt, gint64 size)
     754             : {
     755             : 
     756       49745 :     if (opt != NULL && opt->adaptive == TRUE)
     757             :         {
     758       49745 :             if (size < 32768)            /* max 64 blocks       */
     759             :                 {
     760             :                     return 512;
     761             :                 }
     762        1174 :             else if (size < 262144)      /* max 128 blocks      */
     763             :                 {
     764             :                     return 2048;
     765             :                 }
     766         242 :             else if (size < 1048576)     /* max 128 blocks      */
     767             :                 {
     768             :                     return 8192;
     769             :                 }
     770          65 :             else if (size < 8388608)     /* max 512 blocks      */
     771             :                 {
     772             :                     return 16384;
     773             :                 }
     774          10 :             else if (size < 67108864)    /* max 1024 blocks     */
     775             :                 {
     776             :                     return 65536;
     777             :                 }
     778           3 :             else if (size < 134217728)   /* max 1024 blocks     */
     779             :                 {
     780           0 :                     opt->buffersize = (CLIENT_MIN_BUFFER) * 2;
     781           0 :                     return 131072;
     782             :                 }
     783             :             else                         /* at least 512 blocks */
     784             :                 {
     785           3 :                     opt->buffersize = (CLIENT_MIN_BUFFER) * 4;
     786           3 :                     return 262144;
     787             :                 }
     788             :         }
     789           0 :     else if (opt != NULL)
     790             :         {
     791             :             /* default case */
     792           0 :              return opt->blocksize;
     793             :         }
     794             :     else
     795             :         {
     796             :             /* default case */
     797             :             return CLIENT_BLOCK_SIZE;
     798             :         }
     799             : }
     800             : 
     801             : 
     802             : /**
     803             :  * Process the file that is not already in our local cache
     804             :  * @param main_struct : main structure of the program
     805             :  * @param meta is the meta data of the file to be processed (it does
     806             :  *             not contain any hashs at that point).
     807             :  */
     808       49742 : static void process_small_file_not_in_cache(main_struct_t *main_struct, meta_data_t *meta)
     809             : {
     810       49742 :     GFile *a_file = NULL;
     811       49742 :     gchar *answer = NULL;
     812       49742 :     gint success = 0;      /** success returns a CURL Error status such as CURLE_OK for instance */
     813       49742 :     a_clock_t *mesure_time = NULL;
     814             : 
     815       49742 :     if (main_struct != NULL && main_struct->opt != NULL && meta != NULL)
     816             :         {
     817             : 
     818       49742 :             print_debug(_("Processing small file: %s\n"), meta->name);
     819             : 
     820       49742 :             if (meta->file_type == G_FILE_TYPE_REGULAR)
     821             :                 {
     822       48779 :                     mesure_time = new_clock_t();
     823             : 
     824             :                     /* Calculates hashs and takes care of data */
     825       48779 :                     a_file = g_file_new_for_path(meta->name);
     826       48779 :                     meta->hash_data_list = calculate_hash_data_list_for_file(a_file, meta->blocksize);
     827       48779 :                     a_file = free_object(a_file);
     828             : 
     829       48779 :                     end_clock(mesure_time, "calculate_hash_data_list");
     830             :                 }
     831             : 
     832       49742 :             mesure_time = new_clock_t();
     833       49742 :             answer = send_meta_data_to_server(main_struct, meta, FALSE);
     834       49742 :             end_clock(mesure_time, "send_meta_data_to_server");
     835             : 
     836       49742 :             mesure_time = new_clock_t();
     837       49742 :             if (meta->size < meta->blocksize)
     838             :                 {
     839             :                     /* Only one block to send (size is less than blocksize's value) */
     840        4720 :                     send_data_to_server(main_struct, meta, answer);
     841             :                 }
     842             :             else
     843             :                 {
     844             :                     /* A least 2 blocks to send */
     845       45022 :                     send_all_data_to_server(main_struct, meta, answer);
     846             :                 }
     847       49742 :             end_clock(mesure_time, "send_(all)_data_to_server");
     848             : 
     849       49742 :             free_variable(answer); /* Not used by now */
     850             : 
     851             :             if (success == CURLE_OK)
     852             :                 {
     853             :                     /* Everything has been transmitted so we can save meta data into the local db cache */
     854             :                     /* This is usefull for file carving to avoid sending too much things to the server  */
     855       49742 :                     mesure_time = new_clock_t();
     856       49742 :                     db_save_meta_data(main_struct->database, meta, TRUE);
     857       49742 :                     end_clock(mesure_time, "db_save_meta_data");
     858             :                 }
     859             :         }
     860       49742 : }
     861             : 
     862             : 
     863             : /**
     864             :  * Process the file that is not already in our local cache
     865             :  * @param main_struct : main structure of the program
     866             :  * @param meta is the meta data of the file to be processed (it does
     867             :  *             not contain any hashs at that point).
     868             :  */
     869           3 : static void process_big_file_not_in_cache(main_struct_t *main_struct, meta_data_t *meta)
     870             : {
     871           3 :     GFile *a_file = NULL;
     872           3 :     gchar *answer = NULL;
     873           3 :     GFileInputStream *stream = NULL;
     874           3 :     GError *error = NULL;
     875           3 :     GList *hash_data_list = NULL;
     876           3 :     hash_data_t *hash_data = NULL;
     877           3 :     gssize read = 0;
     878           3 :     guchar *buffer = NULL;
     879           3 :     GChecksum *checksum = NULL;
     880           3 :     guint8 *a_hash = NULL;
     881           3 :     gsize digest_len = HASH_LEN;
     882           3 :     gsize read_bytes = 0;
     883           3 :     json_t *array = NULL;
     884           3 :     json_t *to_insert = NULL;
     885           3 :     a_clock_t *elapsed = NULL;
     886             : 
     887           3 :     if (main_struct != NULL && main_struct->opt != NULL && meta != NULL)
     888             :         {
     889           3 :             a_file = g_file_new_for_path(meta->name);
     890           3 :             print_debug(_("Processing file: %s\n"), meta->name);
     891             : 
     892           3 :             if (a_file != NULL)
     893             :                 {
     894           3 :                     stream = g_file_read(a_file, NULL, &error);
     895             : 
     896           3 :                     if (stream != NULL && error == NULL)
     897             :                         {
     898             : 
     899           3 :                             checksum = g_checksum_new(G_CHECKSUM_SHA256);
     900           3 :                             buffer = (guchar *) g_malloc(meta->blocksize);
     901           3 :                             a_hash = (guint8 *) g_malloc(digest_len);
     902             : 
     903           3 :                             read = g_input_stream_read((GInputStream *) stream, buffer, meta->blocksize, NULL, &error);
     904           3 :                             read_bytes = read_bytes + read;
     905           3 :                             array = json_array();
     906             : 
     907        5269 :                             while (read != 0 && error == NULL)
     908             :                                 {
     909        5263 :                                     g_checksum_update(checksum, buffer, read);
     910        5263 :                                     g_checksum_get_digest(checksum, a_hash, &digest_len);
     911             : 
     912             :                                     /* Need to save data and read in hash_data_t structure */
     913        5263 :                                     hash_data = new_hash_data_t(buffer, read, a_hash);
     914             : 
     915        5263 :                                     to_insert = convert_hash_data_t_to_json(hash_data);
     916        5263 :                                     json_array_append_new(array, to_insert);
     917             : 
     918             :                                     /* Only keeping hashs in the list */
     919        5263 :                                     hash_data->data = free_variable(hash_data->data);
     920        5263 :                                     hash_data_list = g_list_prepend(hash_data_list, hash_data);
     921             : 
     922        5263 :                                     g_checksum_reset(checksum);
     923        5263 :                                     digest_len = HASH_LEN;
     924             : 
     925        5263 :                                     if (read_bytes >= main_struct->opt->buffersize)
     926             :                                         {
     927             :                                             /* sending datas naïvely */
     928         327 :                                             elapsed = new_clock_t();
     929         327 :                                             print_debug(_("Sending data: %d bytes\n"), read_bytes);
     930         327 :                                             insert_array_in_root_and_send(main_struct, array);
     931         327 :                                             array = json_array();
     932         327 :                                             read_bytes = 0;
     933         327 :                                             end_clock(elapsed, "insert_array_in_root_and_send");
     934             :                                         }
     935             : 
     936        5263 :                                     buffer = (guchar *) g_malloc(meta->blocksize);
     937        5263 :                                     a_hash = (guint8 *) g_malloc(digest_len);
     938        5263 :                                     read = g_input_stream_read((GInputStream *) stream, buffer, meta->blocksize, NULL, &error);
     939        5263 :                                     read_bytes = read_bytes + read;
     940             :                                 }
     941             : 
     942           3 :                             if (error != NULL)
     943             :                                 {
     944           0 :                                     print_error(__FILE__, __LINE__, _("Error while reading file: %s\n"), error->message);
     945           0 :                                     error = free_error(error);
     946           0 :                                     g_list_free_full(hash_data_list, free_hdt_struct);
     947           0 :                                     hash_data_list =  NULL;
     948             :                                 }
     949             :                             else
     950             :                                 {
     951             : 
     952             :                                     /* sending datas naïvely */
     953           3 :                                     if (read_bytes > 0)
     954             :                                         {
     955           3 :                                             elapsed = new_clock_t();
     956           3 :                                             print_debug(_("Sending data: %d bytes\n"), read_bytes);
     957           3 :                                             insert_array_in_root_and_send(main_struct, array);
     958           3 :                                             end_clock(elapsed, "insert_array_in_root_and_send");
     959             :                                         }
     960             : 
     961             :                                     /* get the list in correct order (because we prepended the hashs to get speed when inserting hashs in the list) */
     962           3 :                                     hash_data_list = g_list_reverse(hash_data_list);
     963             :                                 }
     964             : 
     965           3 :                             free_variable(buffer);
     966           3 :                             free_variable(a_hash);
     967           3 :                             g_checksum_free(checksum);
     968           3 :                             g_input_stream_close((GInputStream *) stream, NULL, NULL);
     969           3 :                             free_object(stream);
     970             :                         }
     971             :                     else
     972             :                         {
     973           0 :                             print_error(__FILE__, __LINE__, _("Unable to open file for reading: %s\n"), error->message);
     974           0 :                             error = free_error(error);
     975             :                         }
     976             : 
     977           3 :                     meta->hash_data_list = hash_data_list;
     978           3 :                     answer = send_meta_data_to_server(main_struct, meta, TRUE);
     979             : 
     980           3 :                     if (answer != NULL)
     981             :                         {   /** @todo may be we should check that answer is something that tells that everything went Ok. */
     982             :                             /* Everything has been transmitted so we can save meta data into the local db cache */
     983             :                             /* This is usefull for file carving to avoid sending too much things to the server  */
     984           3 :                             elapsed = new_clock_t();
     985           3 :                             db_save_meta_data(main_struct->database, meta, TRUE);
     986           3 :                             end_clock(elapsed, "db_save_meta_data");
     987             :                         }
     988             : 
     989           3 :                     a_file = free_object(a_file);
     990             :                 }
     991             :         }
     992           3 : }
     993             : 
     994             : 
     995             : /**
     996             :  * This function gets meta data and data from a file and sends them
     997             :  * to the server in order to save the file located in the directory
     998             :  * 'directory' and represented by 'fileinfo' variable.
     999             :  * @param main_struct : main structure of the program
    1000             :  * @param directory is the directory we are iterating over
    1001             :  * @param fileinfo is a glib structure that contains all meta data and
    1002             :  *        more for a file.
    1003             :  * @note This function is not threadable as is. One may have problems
    1004             :  *       when writing to the database for instance.
    1005             :  */
    1006       51772 : void save_one_file(main_struct_t *main_struct, file_event_t *file_event)
    1007             : {
    1008       51772 :     meta_data_t *meta = NULL;
    1009       51772 :     a_clock_t *my_clock = NULL;
    1010       51772 :     gchar *message = NULL;
    1011       51772 :     gchar *another_dir = NULL;
    1012       51772 :     filter_file_t *filter = NULL;
    1013             : 
    1014       51772 :     if (main_struct != NULL && file_event != NULL)
    1015             :         {
    1016       51772 :             my_clock = new_clock_t();
    1017             : 
    1018             :             /* Get data and meta_data for a file. */
    1019      103544 :             filter = new_filter_t(main_struct->database, main_struct->regex_exclude_list, FALSE);
    1020       51772 :             meta = get_meta_data_from_fileinfo(file_event, filter, main_struct->opt);
    1021             : 
    1022             :             /* We want to save all files that are not excluded ie filter->excluded not TRUE */
    1023       51772 :             if (meta != NULL && filter != NULL && filter->excluded == FALSE)
    1024             :                 {
    1025       49745 :                     if (meta->in_cache == FALSE)
    1026             :                         {
    1027             :                              /* File is not in cache thus unknown thus we need to save it */
    1028       49745 :                             if (meta->size < CLIENT_SMALL_FILE_SIZE)
    1029             :                                 {
    1030       49742 :                                     process_small_file_not_in_cache(main_struct, meta);
    1031             :                                 }
    1032             :                             else
    1033             :                                 {
    1034           3 :                                     process_big_file_not_in_cache(main_struct, meta);
    1035             :                                 }
    1036             :                         }
    1037             : 
    1038       49745 :                     if (meta->file_type == G_FILE_TYPE_DIRECTORY)
    1039             :                         {
    1040             :                             /* This is a recursive call */
    1041         329 :                             another_dir = g_strdup(meta->name);
    1042         329 :                             g_async_queue_push(main_struct->dir_queue, another_dir);
    1043             : 
    1044             :                         }
    1045       49745 :                     message = g_strdup_printf(_("processing file %s"), meta->name);
    1046       49745 :                     free_meta_data_t(meta, FALSE);
    1047             :                     free_filter_file_t(filter);
    1048             :                 }
    1049        2027 :             else if (meta != NULL && filter != NULL && filter->excluded == TRUE)
    1050             :                 {
    1051        2027 :                     message = g_strdup_printf(_("processing excluded file %s"), meta->name);
    1052        2027 :                     free_meta_data_t(meta, FALSE);
    1053             :                     free_filter_file_t(filter);
    1054             :                 }
    1055             :             else
    1056             :                 {
    1057           0 :                     message = g_strdup_printf(_("Error with meta (%p) or filter (%p) structures\n"), meta, filter);
    1058           0 :                     print_error(__FILE__, __LINE__, message);
    1059             :                 }
    1060             : 
    1061       51772 :             end_clock(my_clock, message);
    1062       51772 :             free_variable(message);
    1063             :         }
    1064       51772 : }
    1065             : 
    1066             : 
    1067             : /**
    1068             :  * Iterates over an enumerator obtained from a directory.
    1069             :  * @param main_struct : main structure of the program
    1070             :  * @param directory is the directory we are iterating over
    1071             :  * @param file_enum is the enumerator obtained when opening a directory
    1072             :  *        to carve it.
    1073             :  */
    1074         333 : static void iterate_over_enum(main_struct_t *main_struct, gchar *directory, GFileEnumerator *file_enum)
    1075             : {
    1076         333 :     GError *error = NULL;
    1077         333 :     GFileInfo *fileinfo = NULL;
    1078         333 :     file_event_t *file_event = NULL;
    1079             : 
    1080         333 :     if (main_struct != NULL && file_enum != NULL)
    1081             :         {
    1082         333 :             fileinfo = g_file_enumerator_next_file(file_enum, NULL, &error);
    1083             : 
    1084       52430 :             while (error == NULL && fileinfo != NULL)
    1085             :                 {
    1086             :                     /* file_event is used and freed in the thread
    1087             :                      * save_one_file_threaded where the queue save_queue
    1088             :                      * is used
    1089             :                      */
    1090       51764 :                     file_event = new_file_event_t(directory, fileinfo);
    1091       51764 :                     g_async_queue_push(main_struct->save_queue, file_event);
    1092             : 
    1093       51764 :                     fileinfo = free_object(fileinfo);
    1094             : 
    1095       51764 :                     fileinfo = g_file_enumerator_next_file(file_enum, NULL, &error);
    1096             :                 }
    1097             :         }
    1098         333 : }
    1099             : 
    1100             : 
    1101             : /**
    1102             :  * Call back for the g_slist_foreach function that carves one directory
    1103             :  * and sub directories in a recursive way.
    1104             :  * @param data is an element of opt->list ie: a gchar * that represents
    1105             :  *        a directory name
    1106             :  * @param user_data is the main_struct_t * pointer to the main structure.
    1107             :  */
    1108         333 : static void carve_one_directory(gpointer data, gpointer user_data)
    1109             : {
    1110         333 :     gchar *directory = (gchar *) data;
    1111         333 :     main_struct_t *main_struct = (main_struct_t *) user_data;
    1112             : 
    1113         333 :     GFile *a_dir = NULL;
    1114         333 :     GFileEnumerator *file_enum = NULL;
    1115         333 :     GError *error = NULL;
    1116             : 
    1117         333 :     if (directory != NULL && main_struct != NULL)
    1118             :         {
    1119         333 :             a_dir = g_file_new_for_path(directory);
    1120         333 :             file_enum = g_file_enumerate_children(a_dir, "*", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &error);
    1121             : 
    1122         333 :             if (error == NULL && file_enum != NULL)
    1123             :                 {
    1124         333 :                     iterate_over_enum(main_struct, directory, file_enum);
    1125         333 :                     g_file_enumerator_close(file_enum, NULL, NULL);
    1126         333 :                     file_enum = free_object(file_enum);
    1127             :                 }
    1128             :             else
    1129             :                 {
    1130           0 :                     print_error(__FILE__, __LINE__, _("Unable to enumerate directory %s: %s\n"), directory, error->message);
    1131           0 :                     error = free_error(error);
    1132             :                 }
    1133             : 
    1134         333 :             a_dir = free_object(a_dir);
    1135             :         }
    1136         333 : }
    1137             : 
    1138             : 
    1139             : /**
    1140             :  * Does carve all directories from the list in the option list.
    1141             :  * This function is a thread that is run at the end of the initialisation
    1142             :  * of main_struct structure.
    1143             :  * @param data: main structure of the program that contains also
    1144             :  *        the options structure that should have a list of directories
    1145             :  *        to save.
    1146             :  */
    1147           1 : static gpointer carve_all_directories(gpointer data)
    1148             : {
    1149           1 :     main_struct_t *main_struct = (main_struct_t *) data;
    1150           1 :     gchar *directory = NULL;
    1151             : 
    1152           1 :     if (main_struct != NULL && main_struct->opt != NULL)
    1153             :         {
    1154           1 :             g_slist_foreach(main_struct->opt->dirname_list, carve_one_directory, main_struct);
    1155             : 
    1156           1 :             directory = g_async_queue_pop(main_struct->dir_queue);
    1157             : 
    1158         330 :             while (directory != NULL)
    1159             :                 {
    1160         329 :                     carve_one_directory(directory, main_struct);
    1161         329 :                     free_variable(directory);
    1162         329 :                     directory = g_async_queue_pop(main_struct->dir_queue);
    1163             :                 }
    1164             :         }
    1165             : 
    1166           0 :     return NULL;
    1167             : }
    1168             : 
    1169             : 
    1170             : /**
    1171             :  * Manages reconnections to the server and the data that may have been
    1172             :  * saved in local buffers while the server was unreachable.
    1173             :  * @param data: main structure of the program that contains also
    1174             :  *        the options structure.
    1175             :  */
    1176           1 : static gpointer reconnected(gpointer data)
    1177             : {
    1178           1 :     main_struct_t *main_struct = (main_struct_t *) data;
    1179             : 
    1180             : 
    1181          41 :     while (main_struct != NULL)
    1182             :         {
    1183          40 :             if (db_is_there_buffers_to_transmit(main_struct->database))
    1184             :                 {
    1185           0 :                     if (is_server_alive(main_struct->reconnected))
    1186             :                         {
    1187           0 :                             print_debug(_("We have data and meta data to transmit to server\n"));
    1188             :                             /* we need to do the job: transmit again the data
    1189             :                              * sleep until we'll implement something
    1190             :                              */
    1191           0 :                             db_transmit_buffers(main_struct->database, main_struct->reconnected);
    1192           0 :                             sleep(CLIENT_RECONNECT_SLEEP_TIME);
    1193             :                         }
    1194             :                     else
    1195             :                         {
    1196           0 :                             sleep(CLIENT_RECONNECT_SLEEP_TIME);
    1197             :                         }
    1198             :                 }
    1199             :             else
    1200             :                 {
    1201          40 :                     sleep(CLIENT_RECONNECT_SLEEP_TIME);
    1202             :                 }
    1203             :         }
    1204             : 
    1205           0 :     return NULL;
    1206             : }
    1207             : 
    1208             : 
    1209             : 
    1210             : /**
    1211             :  * Main function
    1212             :  * @param argc : number of arguments given on the command line.
    1213             :  * @param argv : an array of strings that contains command line arguments.
    1214             :  * @returns always 0
    1215             :  */
    1216           3 : int main(int argc, char **argv)
    1217             : {
    1218           3 :     options_t *opt = NULL;  /** Structure to manage options from the command line can be freed when no longer needed */
    1219           3 :     main_struct_t *main_struct = NULL;
    1220             : 
    1221             :     #if !GLIB_CHECK_VERSION(2, 36, 0)
    1222             :         g_type_init();  /** g_type_init() is deprecated since glib 2.36 */
    1223             :     #endif
    1224             : 
    1225           3 :     init_international_languages();
    1226             : 
    1227             :     /* Global curl initialisation to avoid curl_easy_init() calls to call it. */
    1228           3 :     curl_global_init(CURL_GLOBAL_ALL);
    1229             : 
    1230           3 :     opt = do_what_is_needed_from_command_line_options(argc, argv);
    1231             : 
    1232           1 :     if (opt != NULL)
    1233             :         {
    1234             :             /**
    1235             :              * Inits the main structure and launches two threads one that
    1236             :              * will save the files with an asynchronous queue and a second
    1237             :              * that will do directory carving. Threads communicates with
    1238             :              * the asynchronous queue.
    1239             :              */
    1240           1 :             main_struct = init_main_structure(opt);
    1241             : 
    1242             :             /** Launching an infinite loop to get modifications done on
    1243             :              * the filesystem (on directories we watch).
    1244             :              * @note fanotify's kernel interface does not provide the events
    1245             :              * needed to know if a file has been deleted or it's attributes
    1246             :              * changed. Enabling this feature even if we know that files
    1247             :              * will never get deleted in our database.
    1248             :              */
    1249           1 :             fanotify_loop(main_struct);
    1250             : 
    1251           1 :             free_options_t(main_struct->opt);
    1252             :         }
    1253             : 
    1254           1 :     return 0;
    1255             : }

Generated by: LCOV version 1.11