LCOV - code coverage report
Current view: top level - restore - restore.c (source / functions) Hit Total Coverage
Test: coverage-restore.info Lines: 196 205 95.6 %
Date: 2016-02-03 22:31:47 Functions: 12 12 100.0 %

          Line data    Source code
       1             : /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
       2             : /*
       3             :  *    restore.c
       4             :  *    This file is part of "Sauvegarde" project.
       5             :  *
       6             :  *    (C) Copyright 2015 - 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 restore.c
      25             :  * This program should be able to restore files.
      26             :  */
      27             : 
      28             : #include "restore.h"
      29             : 
      30             : static res_struct_t *init_res_struct(int argc, char **argv);
      31             : static gchar *encode_to_base64(gchar *string);
      32             : static query_t *get_user_infos(gchar *hostname, gchar *filename, options_t *opt);
      33             : static gchar *add_on_field_to_request(gchar *request, gchar *field, gchar *value);
      34             : static gchar *make_base_request(query_t *query);
      35             : static GSList *get_files_from_server(res_struct_t *res_struct, query_t *query);
      36             : static void print_all_files(res_struct_t *res_struct, query_t *query);
      37             : static void restore_data_to_stream(res_struct_t *res_struct, GFileOutputStream *stream, GList *hash_list);
      38             : static void create_file(res_struct_t *res_struct, meta_data_t *meta);
      39             : static void restore_last_file(res_struct_t *res_struct, query_t *query);
      40             : static void free_res_struct_t(res_struct_t *res_struct);
      41             : 
      42             : 
      43             : /**
      44             :  * Inits a res_struct_t * structure. Manages the command line options.
      45             :  * @param argc : number of arguments given on the command line.
      46             :  * @param argv : an array of strings that contains command line arguments.
      47             :  * @returns a res_struct_t * structure containing all of what is needed
      48             :  *          by cdpfglrestore program.
      49             :  */
      50          15 : static res_struct_t *init_res_struct(int argc, char **argv)
      51             : {
      52          15 :     res_struct_t *res_struct = NULL;
      53          15 :     gchar *conn = NULL;
      54             : 
      55             : 
      56          15 :     res_struct = (res_struct_t *) g_malloc0(sizeof(res_struct_t));
      57             : 
      58          15 :     res_struct->hostname = (gchar *) g_get_host_name();
      59             : 
      60          15 :     res_struct->opt = do_what_is_needed_from_command_line_options(argc, argv);
      61             : 
      62          12 :     if (res_struct->opt != NULL && res_struct->opt->ip != NULL)
      63             :         {
      64             :             /* We keep conn string into comm_t structure: do not free it ! */
      65          12 :             conn = make_connexion_string(res_struct->opt->ip, res_struct->opt->port);
      66          12 :             res_struct->comm = init_comm_struct(conn);
      67             :         }
      68             :     else
      69             :         {
      70             :             /* This should never happen because we have default values... */
      71           0 :             res_struct->comm = NULL;
      72             :         }
      73             : 
      74          12 :     return res_struct;
      75             : }
      76             : 
      77             : 
      78             : /**
      79             :  * Encodes a gchar string into a base64 formated gchar * string.
      80             :  * @param string is the gchar string to be encoded (MUST be 0 terminated).
      81             :  * @returns a newly allocated gchar * string in base64 or NULL.
      82             :  */
      83          48 : static gchar *encode_to_base64(gchar *string)
      84             : {
      85          48 :     gchar *encoded_string = NULL;
      86             : 
      87          48 :     if (string != NULL)
      88             :         {
      89          15 :             encoded_string = g_base64_encode((const guchar *) string, strlen(string));
      90             :         }
      91             : 
      92          48 :     return encoded_string;
      93             : }
      94             : 
      95             : 
      96             : 
      97             : /**
      98             :  * Gets all user infos and fills a query_t * structure accordingly.
      99             :  * @param hostname the hostname where the program is run
     100             :  * @param filename is the name of the file we want to restore.
     101             :  * @param opt is the option structure that contains all options.
     102             :  * @return a pointer to a newly allocated query_t structure that may be
     103             :  *         freed when no longer needed.
     104             :  */
     105          12 : static query_t *get_user_infos(gchar *hostname, gchar *filename, options_t *opt)
     106             : {
     107             :     uid_t uid;
     108          12 :     struct passwd *pass = NULL;
     109          12 :     struct group *grp = NULL;
     110          12 :     query_t *query = NULL;
     111          12 :     gchar *the_uid = NULL;
     112          12 :     gchar *the_gid = NULL;
     113          12 :     gchar *owner = NULL;
     114          12 :     gchar *group = NULL;
     115          12 :     gchar *encoded_date = NULL;
     116          12 :     gchar *encoded_filename = NULL;
     117          12 :     gchar *encoded_afterdate = NULL;
     118          12 :     gchar *encoded_beforedate = NULL;
     119             : 
     120          12 :     uid = geteuid();
     121          12 :     pass = getpwuid(uid);
     122             : 
     123          12 :     if (pass != NULL)
     124             :         {
     125          12 :             grp = getgrgid(pass->pw_gid);
     126          12 :             group = g_strdup(grp->gr_name);
     127          12 :             owner = g_strdup(pass->pw_name);
     128          12 :             the_uid = g_strdup_printf("%d", uid);
     129          12 :             the_gid = g_strdup_printf("%d", pass->pw_gid);
     130             : 
     131          12 :             encoded_filename = encode_to_base64(filename);
     132          12 :             encoded_date = encode_to_base64(opt->date);
     133          12 :             encoded_afterdate = encode_to_base64(opt->afterdate);
     134          12 :             encoded_beforedate = encode_to_base64(opt->beforedate);
     135             : 
     136          12 :             query = init_query_t(hostname, the_uid, the_gid, owner, group, encoded_filename, encoded_date, encoded_afterdate, encoded_beforedate);
     137          12 :             print_debug(_("hostname: %s, uid: %s, gid: %s, owner: %s, group: %s\n"), hostname, the_uid, the_gid, owner, group);
     138             :         }
     139             : 
     140          12 :     return query;
     141             : }
     142             : 
     143             : 
     144             : /**
     145             :  * Adds a field and its value to the request
     146             :  * @param request is the request where to add the field and its value.
     147             :  *        This variable is freed here. Do not use its pointer after this
     148             :  *        call !
     149             :  * @param field is the field to be added to the request
     150             :  * @param value is the value of the field
     151             :  * @returns a newly allocated gchar * request that may be freed when no
     152             :  *          longer needed.
     153             :  */
     154          36 : static gchar *add_on_field_to_request(gchar *request, gchar *field, gchar *value)
     155             : {
     156          36 :     gchar *new_request = NULL;
     157             : 
     158          36 :     if (request != NULL && field != NULL && value != NULL)
     159             :         {
     160           3 :             new_request = g_strconcat(request, "&", field, "=", value, NULL);
     161             :         }
     162             :     else
     163             :         {
     164          33 :             new_request = g_strdup(request);
     165             :         }
     166             : 
     167          36 :     free_variable(request);
     168          36 :     request = new_request;
     169             : 
     170          36 :     return new_request;
     171             : }
     172             : 
     173             : 
     174             : /**
     175             :  * Makes the base URL for all requests
     176             :  * @param query is the structure that contains everything needed to
     177             :  *        query the server (and filter a bit). It must not be NULL.
     178             :  * @returns always returns a newly allocated gchar * that represents
     179             :  *          the base of the right part of the URL for all requests.
     180             :  */
     181          12 : static gchar *make_base_request(query_t *query)
     182             : {
     183          12 :     gchar *request = NULL;
     184             : 
     185          12 :     if (query != NULL)
     186             :         {
     187             :             /* This is the base request */
     188          12 :             request = g_strdup_printf("/File/List.json?hostname=%s&uid=%s&gid=%s&owner=%s&group=%s&filename=%s", query->hostname, query->uid, query->gid, query->owner, query->group, query->filename);
     189             :         }
     190             :     else
     191             :         {
     192           0 :              request = g_strdup_printf("/File/List.json?");
     193             :         }
     194             : 
     195          12 :     return request;
     196             : }
     197             : 
     198             : 
     199             : /**
     200             :  * Gets the file the server_meta_data_t * file list if any
     201             :  * @param res_struct is the main structure for cdpfglrestore program.
     202             :  * @param query is the structure that contains everything needed to
     203             :  *        query the server (and filter a bit). It must not be NULL.
     204             :  * @returns a GSList * of server_meta_data_t *
     205             :  */
     206          12 : static GSList *get_files_from_server(res_struct_t *res_struct, query_t *query)
     207             : {
     208          12 :     gchar *request = NULL;
     209          12 :     json_t *root = NULL;
     210          12 :     GSList *list = NULL;    /** List of server_meta_data_t * returned by this function */
     211          12 :     gint res = CURLE_FAILED_INIT;
     212             : 
     213          12 :     if (res_struct != NULL && query != NULL)
     214             :         {
     215          12 :             request = make_base_request(query);
     216          12 :             request = add_on_field_to_request(request, "date", query->date);
     217          12 :             request = add_on_field_to_request(request, "afterdate", query->afterdate);
     218          12 :             request = add_on_field_to_request(request, "beforedate", query->beforedate);
     219             : 
     220          12 :             print_debug(_("Query is: %s\n"), request);
     221          12 :             res = get_url(res_struct->comm, request);
     222             : 
     223          12 :             if (res == CURLE_OK && res_struct->comm->buffer != NULL)
     224             :                 {
     225          12 :                     root = load_json(res_struct->comm->buffer);
     226             : 
     227          12 :                     list = extract_smeta_gslist_from_file_list(root);
     228          12 :                     list = g_slist_sort(list, compare_filenames);
     229             : 
     230          12 :                     json_decref(root);
     231          12 :                     res_struct->comm->buffer = free_variable(res_struct->comm->buffer);
     232             :                 }
     233             : 
     234          12 :             free_variable(request);
     235             :         }
     236             : 
     237          12 :     return list;
     238             : }
     239             : 
     240             : 
     241             : /**
     242             :  * Prints all saved files
     243             :  * @param res_struct is the main structure for cdpfglrestore program.
     244             :  * @param query is the structure that contains everything needed to
     245             :  *        query the server (and filter a bit). It must not be NULL.
     246             :  */
     247           4 : static void print_all_files(res_struct_t *res_struct, query_t *query)
     248             : {
     249           4 :     GSList *list = NULL;   /** List of server_meta_data_t * */
     250           4 :     GSList *head = NULL;   /** head of the list to be freed  */
     251           4 :     server_meta_data_t *smeta = NULL;
     252             : 
     253           4 :     if (res_struct != NULL && query != NULL)
     254             :         {
     255           4 :             list = get_files_from_server(res_struct, query);
     256           4 :             head = list;
     257             : 
     258         182 :             while (list != NULL)
     259             :                 {
     260         174 :                     smeta = (server_meta_data_t *) list->data;
     261         174 :                     print_smeta_to_screen(smeta);
     262         174 :                     free_smeta_data_t(smeta);
     263             : 
     264         174 :                     list = g_slist_next(list);
     265             :                 }
     266             : 
     267           4 :             g_slist_free(head);
     268             :         }
     269           4 : }
     270             : 
     271             : 
     272             : /**
     273             :  * Writes data obtained from the server with the hash_list hashs
     274             :  * to the stream.
     275             :  * @param stream is the stream where we are writing data (MUST be opened
     276             :  *        and not NULL)
     277             :  * @param hash_list list of hashs of the file to be restored
     278             :  * @todo error management.
     279             :  */
     280           4 : static void restore_data_to_stream(res_struct_t *res_struct, GFileOutputStream *stream, GList *hash_list)
     281             : {
     282           4 :     gchar *hash = NULL;
     283           4 :     hash_data_t *hash_data = NULL;
     284           4 :     GError *error = NULL;
     285           4 :     gchar *request = NULL;
     286           4 :     gint res = CURLE_FAILED_INIT;
     287             : 
     288           4 :     if (stream != NULL)
     289             :         {
     290         100 :             while (hash_list != NULL)
     291             :                 {
     292          96 :                     hash_data = hash_list->data;
     293          96 :                     hash = hash_to_string(hash_data->hash);
     294          96 :                     request = g_strdup_printf("/Data/%s.json", hash);
     295             : 
     296          96 :                     print_debug(_("Query is: %s\n"), request);
     297             : 
     298             :                     /* This call fills res_struct->comm->buffer */
     299          96 :                     res = get_url(res_struct->comm, request);
     300             : 
     301          96 :                     if (res == CURLE_OK)
     302             :                         {
     303             :                             /** We need to save the retrieved buffer */
     304          96 :                             if (res_struct->comm->buffer != NULL)
     305             :                                 {
     306          96 :                                     hash_data = convert_string_to_hash_data(res_struct->comm->buffer);
     307          96 :                                     res_struct->comm->buffer = free_variable(res_struct->comm->buffer);
     308             : 
     309          96 :                                     if (hash_data != NULL)
     310             :                                         {
     311          96 :                                             g_output_stream_write((GOutputStream *) stream, hash_data->data, hash_data->read, NULL, &error);
     312             : 
     313          96 :                                             free_hash_data_t(hash_data);
     314             :                                         }
     315             :                                     else
     316             :                                         {
     317           0 :                                             print_error(__FILE__, __LINE__, _("Error while trying to restore %s hash\n"), hash);
     318             :                                         }
     319             :                                 }
     320             :                         }
     321             :                     else
     322             :                         {
     323           0 :                             print_error(__FILE__, __LINE__, _("Error while getting hash %s"), hash);
     324             :                         }
     325             : 
     326          96 :                     hash_list = g_list_next(hash_list);
     327          96 :                     free_variable(request);
     328          96 :                     free_variable(hash);
     329             :                 }
     330             :         }
     331           4 : }
     332             : 
     333             : 
     334             : /**
     335             :  * Creates the file to be restored.
     336             :  * @param res_struct is the main structure for cdpfglrestore program (used here
     337             :  *        to communicate with cdpfglserver's server).
     338             :  * @param meta is the whole meta_data file describing the file to be
     339             :  *        restored
     340             :  */
     341           4 : static void create_file(res_struct_t *res_struct, meta_data_t *meta)
     342             : {
     343           4 :     GFile *file = NULL;
     344           4 :     gchar *basename = NULL;    /** basename for the file to be restored     */
     345           4 :     gchar *where = NULL;       /** directory where to restore the file      */
     346           4 :     gchar *filename = NULL;    /** filename of the restored file            */
     347           4 :     GFileOutputStream *stream =  NULL;
     348           4 :     GError *error = NULL;
     349           4 :     options_t *opt = NULL;
     350             : 
     351           4 :     if (res_struct != NULL && meta != NULL)
     352             :         {
     353             :             /* get the basename of the file to be restored */
     354           4 :             basename = g_path_get_basename(meta->name);
     355             : 
     356           4 :             opt = res_struct->opt;
     357             : 
     358           4 :             if (opt != NULL && opt->where != NULL && g_file_test(opt->where, G_FILE_TEST_IS_DIR))
     359             :                 {
     360           4 :                     where = g_strdup(opt->where);
     361             :                 }
     362             : 
     363           4 :             if (where == NULL)
     364             :                 {
     365             :                     /* Fall back to get the current directory to make the file to be restored in it */
     366           0 :                     where = g_get_current_dir();
     367             :                 }
     368             : 
     369           4 :             filename = g_build_filename(where, basename, NULL);
     370           4 :             print_debug(_("filename to restore: %s\n"), filename);
     371           4 :             file = g_file_new_for_path(filename);
     372             : 
     373           4 :             if (g_strcmp0("", meta->link) == 0)
     374             :                 {
     375           4 :                     stream = g_file_replace(file, NULL, TRUE, G_FILE_CREATE_NONE, NULL, &error);
     376             : 
     377           4 :                     if (stream != NULL)
     378             :                         {
     379           4 :                             restore_data_to_stream(res_struct, stream, meta->hash_data_list);
     380             : 
     381           4 :                             g_output_stream_close((GOutputStream *) stream, NULL, &error);
     382           4 :                             free_object(stream);
     383             :                         }
     384           0 :                     else if (error != NULL)
     385             :                         {
     386           0 :                             print_error(__FILE__, __LINE__, _("Error: unable to open file %s to write data in it (%s).\n"), filename, error->message);
     387           0 :                             free_variable(error);
     388             :                         }
     389             : 
     390             :                     /* Setting before closing the file does not alter access and modification time */
     391           4 :                     set_file_attributes(file, meta);
     392             :                 }
     393             :             else
     394             :                 {
     395           0 :                     make_symbolic_link(file, meta->link);
     396             :                 }
     397             : 
     398           4 :             free_object(file);
     399           4 :             free_variable(where);
     400           4 :             free_variable(basename);
     401           4 :             free_variable(filename);
     402             :         }
     403           4 : }
     404             : 
     405             : 
     406             : /**
     407             :  * Restores the last file that the fetched list contains.
     408             :  * @param res_struct is the main structure for cdpfglrestore program.
     409             :  * @param query is the structure that contains everything needed to
     410             :  *        query the server (and filter a bit). It must not be NULL.
     411             :  */
     412           8 : static void restore_last_file(res_struct_t *res_struct, query_t *query)
     413             : {
     414           8 :     GSList *list = NULL;      /** List of server_meta_data_t *             */
     415           8 :     GSList *last = NULL;      /** last element of the list                 */
     416           8 :     server_meta_data_t *smeta = NULL;
     417           8 :     meta_data_t *meta = NULL;
     418           8 :     gchar *string_inode = NULL;
     419           8 :     gchar *string_atime = NULL;
     420           8 :     gchar *string_ctime = NULL;
     421           8 :     gchar *string_mtime = NULL;
     422           8 :     gchar *string_size = NULL;
     423             : 
     424           8 :     if (res_struct != NULL && query != NULL)
     425             :         {
     426           8 :             list = get_files_from_server(res_struct, query);
     427           8 :             last = g_slist_last(list);
     428             : 
     429           8 :             if (last != NULL)
     430             :                 {
     431           4 :                     smeta = (server_meta_data_t *) last->data;
     432           4 :                     meta = smeta->meta;
     433             : 
     434           4 :                     if (get_debug_mode() == TRUE)
     435             :                         {
     436           4 :                             string_inode = g_strdup_printf("%"G_GUINT64_FORMAT, meta->inode);
     437           4 :                             string_atime = g_strdup_printf("%"G_GUINT64_FORMAT, meta->atime);
     438           4 :                             string_ctime = g_strdup_printf("%"G_GUINT64_FORMAT, meta->ctime);
     439           4 :                             string_mtime = g_strdup_printf("%"G_GUINT64_FORMAT, meta->mtime);
     440           4 :                             string_size = g_strdup_printf("%"G_GUINT64_FORMAT, meta->size);
     441             : 
     442           4 :                             print_debug(_("File to be restored: type %d, inode: %s, mode: %d, atime: %s, ctime: %s, mtime: %s, size: %s, filename: %s, owner: %s, group: %s, uid: %d, gid: %d\n"), meta->file_type, string_inode, meta->mode, string_atime, string_ctime, string_mtime, string_size, meta->name, meta->owner, meta->group, meta->uid, meta->gid);
     443             : 
     444           4 :                             free_variable(string_inode);
     445           4 :                             free_variable(string_atime);
     446           4 :                             free_variable(string_ctime);
     447           4 :                             free_variable(string_mtime);
     448           4 :                             free_variable(string_size);
     449             :                         }
     450             : 
     451           4 :                     create_file(res_struct, meta);
     452             :                 }
     453             : 
     454           8 :             g_slist_free_full(list, gslist_free_smeta);
     455             :         }
     456           8 : }
     457             : 
     458             : 
     459             : /**
     460             :  * Frees a previously allocated res_struct_t * structure.
     461             :  * @param res_struct is the res_struct_t * structure to be freed.
     462             :  */
     463          12 : static void free_res_struct_t(res_struct_t *res_struct)
     464             : {
     465          12 :     if (res_struct != NULL)
     466             :         {
     467          12 :             free_options_t(res_struct->opt);
     468          12 :             free_comm_t(res_struct->comm);
     469          12 :             free_variable(res_struct->hostname);
     470          12 :             free_variable(res_struct);
     471             :         }
     472          12 : }
     473             : 
     474             : 
     475             : /**
     476             :  * Main function
     477             :  * @param argc : number of arguments given on the command line.
     478             :  * @param argv : an array of strings that contains command line arguments.
     479             :  * @returns
     480             :  */
     481          15 : int main(int argc, char **argv)
     482             : {
     483          15 :     res_struct_t *res_struct = NULL;
     484          15 :     query_t *query =  NULL;
     485             : 
     486             : 
     487             :     #if !GLIB_CHECK_VERSION(2, 36, 0)
     488             :         g_type_init();  /** g_type_init() is deprecated since glib 2.36 */
     489             :     #endif
     490             : 
     491          15 :     init_international_languages();
     492             : 
     493          15 :     res_struct = init_res_struct(argc, argv);
     494             : 
     495          12 :     if (res_struct != NULL && res_struct->opt != NULL && res_struct->comm != NULL)
     496             :         {
     497             : 
     498          12 :             if (res_struct->opt->list != NULL)
     499             :                 {
     500           4 :                     query = get_user_infos(res_struct->hostname, res_struct->opt->list, res_struct->opt);
     501           4 :                     print_all_files(res_struct, query);
     502           4 :                     free_query_t(query);
     503             :                 }
     504             : 
     505          12 :             if (res_struct->opt->restore != NULL)
     506             :                 {
     507           8 :                     query = get_user_infos(res_struct->hostname, res_struct->opt->restore, res_struct->opt);
     508           8 :                     restore_last_file(res_struct, query);
     509           8 :                     free_query_t(query);
     510             :                 }
     511             : 
     512          12 :             free_res_struct_t(res_struct);
     513             : 
     514          12 :             return EXIT_SUCCESS;
     515             :         }
     516             :     else
     517             :         {
     518             :             return EXIT_FAILURE;
     519             :         }
     520             : }

Generated by: LCOV version 1.11