1 /*********************************************************************/
2 // dar - disk archive - a backup/restoration program
3 // Copyright (C) 2002-2052 Denis Corbin
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 //
19 // to contact the author : http://dar.linux.free.fr/email.html
20 /*********************************************************************/
21 
22 /// \defgroup Tools Tools
23 /// \brief a set of tool routine
24 ///
25 /// these routines are available from libdar for historical
26 /// reason, but are not part of the API.
27 /// They are shared and used by dar, dar_slave, dar_xform,
28 /// and dar_manager command. You should avoid using them in
29 /// external program as they may be removed or changed without
30 /// backward compatibility support.
31 
32 /// \file tools.hpp
33 /// \brief a set of general purpose routines
34 /// \ingroup Tools
35 
36 
37 #ifndef TOOLS_HPP
38 #define TOOLS_HPP
39 
40 #include "../my_config.h"
41 
42 extern "C"
43 {
44 #if STDC_HEADERS
45 #include <stdarg.h>
46 #endif
47 #if HAVE_SIGNAL_H
48 #include <signal.h>
49 #endif
50 #if HAVE_GPGME_H
51 #include <gpgme.h>
52 #endif
53 }
54 
55 #include <string>
56 #include <vector>
57 #include <map>
58 #include "path.hpp"
59 #include "infinint.hpp"
60 #include "generic_file.hpp"
61 #include "tuyau.hpp"
62 #include "integers.hpp"
63 #include "tlv_list.hpp"
64 #include "memory_pool.hpp"
65 #include "datetime.hpp"
66 
67 #define TOOLS_SI_SUFFIX 1000
68 #define TOOLS_BIN_SUFFIX 1024
69 
70 namespace libdar
71 {
72 
73 	/// \addtogroup Tools
74 	/// @{
75 
76 
77 	/// libdar internal use only: it is launched from get_version() and initializes tools internal variables
78     extern void tools_init();
79 	/// libdar internal use only: it is launched from close_and_clean() and releases tools internal variables
80     extern void tools_end();
81 
82 	/// convert a string to a char *
83 
84 	/// \param[in] x is the string to convert
85 	/// \return the address of newly allocated memory containing the equivalent string as the argument
86 	/// \exception Ememory is thrown if the memory allocation failed, this call never return nullptr
87 	/// \note Do not use this function, use std::string::c_str(). The allocated memory must be released by the caller thanks to the "delete []" operator
88     extern char *tools_str2charptr(const std::string &x);
89 
90 	/// write a string to a file with a '\\0' at then end
91 
92 	/// \param[in] f the file to write to
93 	/// \param[in] s the string to write to file
94     extern void tools_write_string(generic_file & f, const std::string & s);
95 
96 	/// read a string from a file expecting it to terminate by '\\0'
97 
98 	/// \param f the file to read from
99 	/// \param s the string to put the data to (except the ending '\\0')
100     extern void tools_read_string(generic_file & f, std::string & s);
101 
102 	/// write a string to a file, '\\0' has no special meaning nor is added at the end
103 
104 	/// \param[in] f the file to write to
105 	/// \param[in] s the string to write to file
106     extern void tools_write_string_all(generic_file & f, const std::string & s);
107 
108 	/// read a string if given size from a file '\\0' has no special meaning
109 
110 	/// \param[in] f is the file to read from
111 	/// \param[in] s is the string to put read data in
112 	/// \param[in] taille is the size in byte to read
113     extern void tools_read_string_size(generic_file & f, std::string & s, infinint taille);
114 
115 	/// retrieve the size in byte of a file
116 
117 	/// \param[in] p is the path to the file which size is to get
118 	/// \return the size of the file in byte
119     extern infinint tools_get_filesize(const path &p);
120 
121 	/// convert the given string to infinint taking care of multiplication suffixes like k, M, T, etc.
122 
123 	/// \param[in] s is the string to read
124 	/// \param[in] base is the multiplication factor (base = 1000 for SI, base = 1024 for computer science use)
125 	/// \return the value encoded in the given string
126     extern infinint tools_get_extended_size(std::string s, U_I base);
127 
128 	/// convert an integer to its decimal representation with the highest unit of metric system
129 	/// \param[in] number is the integer to convert
130 	/// \param[in] unit unit symbol (o for octet, m for meter, etc.) to apply metric system to, this may be nullptr
131 	/// \param[in] binary if set to true using the ki, Gi, Mi ... scale instead of the traditional k, G, M, ... prefixes
132 	/// \return the string representing the number in metric system (ex: "1 ko", "200 Mio", ...)
133     extern std::string tools_display_integer_in_metric_system(infinint number, const std::string & unit, bool binary);
134 
135 	/// extracts the basename of a file (removing path part)
136 
137 	/// \param[in] command_name is the full path of the file
138 	/// \param[out] basename the basename of the file
139 	/// \exception Ememory can be thrown if memory allocation failed
140     extern void tools_extract_basename(const char *command_name, std::string & basename);
141 
142 
143 	/// give a pointer to the last character of the given value in the given string
144 
145 	/// \param[in] s is the given string
146 	/// \param[in] v is the given char value
147 	/// \return a interator on s, pointing on the last char of s equal to v or a pointing to s.end() if no such char could be found is "s"
148 	/// \note the arguments are not modified neither the data they are pointing to. However the const statement has not been used to
149 	/// be able to return a iterator on the string (and not a const_interator). There is probably other ways to do that (using const_cast) for example
150     extern std::string::iterator tools_find_last_char_of(std::string &s, unsigned char v);
151 
152 	/// give a pointer to the last character of the given value in the given string
153 
154 	/// \param[in] s is the given string
155 	/// \param[in] v is the given char value
156 	/// \return a interator on s, pointing on the first char of s equal to v or a pointing to s.end() if no such char could be found is "s"
157 	/// \note the arguments are not modified neither the data they are pointing to. However the const statement has not been used to
158 	/// be able to return a iterator on the string (and not a const_interator). There is probably other ways to do that (using const_cast) for example
159     extern std::string::iterator tools_find_first_char_of(std::string &s, unsigned char v);
160 
161 	/// split a given full path in path part and basename part
162 
163 	/// \param[in] all is the path to split
164 	/// \param[out] chemin is the resulting path part, it points to a newly allocated path object
165 	/// \param[out] base is the resulting basename
166 	/// \param[in] pool memory pool to use for allocation or nullptr for default memory allocation
167 	/// \note chemin argument must be release by the caller thanks to the "delete" operator.
168     extern void tools_split_path_basename(const char *all, path * &chemin, std::string & base, memory_pool *pool = nullptr);
169 
170 	/// split a given full path in path part and basename part
171 
172 	/// \param[in] all is the path to split
173 	/// \param[out] chemin is the resulting path part, it points to a newly allocated path object
174 	/// \param[out] base is the resulting basename
175 	/// \param[in] pool memory pool to use for allocation or nullptr for default memory allocation
176 	/// \note chemin argument must be release by the caller thanks to the "delete" operator.
177     extern void tools_split_path_basename(const std::string &all, std::string & chemin, std::string & base, memory_pool *pool = nullptr);
178 
179 	/// open a pair of tuyau objects encapsulating two named pipes.
180 
181 	/// \param[in,out] dialog for user interaction
182 	/// \param[in] input path to the input named pipe
183 	/// \param[in] output path to the output named pipe
184 	/// \param[out] in resulting tuyau object for input
185 	/// \param[out] out resulting tuyau object for output
186 	/// \param[in] pool memory pool to use for allocation or nullptr for default memory allocation
187 	/// \note in and out parameters must be released by the caller thanks to the "delete" operator
188     extern void tools_open_pipes(user_interaction & dialog,
189 				 const std::string &input,
190 				 const std::string & output,
191                                  tuyau *&in,
192 				 tuyau *&out,
193 				 memory_pool *pool = nullptr);
194 
195 	/// set blocking/not blocking mode for reading on a file descriptor
196 
197 	/// \param[in] fd file descriptor to read on
198 	/// \param[in] mode set to true for a blocking read and to false for non blocking read
199     extern void tools_blocking_read(int fd, bool mode);
200 
201 	/// convert uid to name in regards to the current system's configuration
202 
203 	/// \param[in] uid the User ID number
204 	/// \return the name of the corresponding user or the uid if none corresponds
205     extern std::string tools_name_of_uid(const infinint & uid);
206 
207 	/// convert gid to name in regards of the current system's configuration
208 
209 	/// \param[in] gid the Group ID number
210 	/// \return the name of the corresponding group or the gid if none corresponds
211     extern std::string tools_name_of_gid(const infinint & gid);
212 
213 	/// convert unsigned word to string
214 
215 	/// \param[in] x the unsigned word to convert
216 	/// \return the decimal representation of the given integer
217     extern std::string tools_uword2str(U_16 x);
218 
219 	/// convert integer to string
220 
221 	/// \param[in] x the integer to convert
222 	/// \return the decimal representation of the given integer
223     extern std::string tools_int2str(S_I x);
224     extern std::string tools_uint2str(U_I x);
225 
226 	/// convert an integer written in decimal notation to the corresponding value
227 
228 	/// \param[in] x the decimal representation of the integer
229 	/// \return the value corresponding to the decimal representation given
230     extern U_I tools_str2int(const std::string & x);
231 
232 	/// convert a signed integer written in decimal notation to the corresponding value
233 
234 	/// \param[in] x the decimal representation of the integer
235 	/// \return the value corresponding to the decimal representation given
236     extern S_I tools_str2signed_int(const std::string & x);
237 
238 	/// ascii to integer conversion
239 
240 	/// \param[in] a is the ascii string to convert
241 	/// \param[out] val is the resulting value
242 	/// \return true if the conversion could be done false if the given string does not
243 	/// correspond to the decimal representation of an unsigned integer
244 	/// \note this call is now a warapper around tools_str2int
245     extern bool tools_my_atoi(const char *a, U_I & val);
246 
247 	/// prepend spaces before the given string
248 
249 	/// \param[in] s the string to append spaces to
250 	/// \param[in] expected_size the minimum size of the resulting string
251 	/// \return a string at least as much long as expected_size with prepended leading spaces if necessary
252     extern std::string tools_addspacebefore(std::string s, U_I expected_size);
253 
254 	/// convert a date in second to its human readable representation
255 
256 	/// \param[in] date the date in second
257 	/// \return the human representation corresponding to the argument
258     extern std::string tools_display_date(const datetime & date);
259 
260 	/// convert a human readable date representation in number of second since the system reference date
261 
262 	/// \param[in] repres the date's human representation
263 	/// \return the corresponding number of seconds (computer time)
264 	/// \note the string expected format is "[[[year/]month/]day-]hour:minute[:second]"
265     extern infinint tools_convert_date(const std::string & repres);
266 
267 	/// wrapper to the "system" system call.
268 
269 	/// \param[in,out] dialog for user interaction
270 	/// \param[in] argvector the equivalent to the argv[] vector
271     extern void tools_system(user_interaction & dialog, const std::vector<std::string> & argvector);
272 
273 	/// wrapper to the "system" system call using anonymous pipe to tranmit arguments to the child process
274 
275 	/// \param[in,out] dialog for user interaction
276 	/// \param[in] dar_cmd the path to the executable to run
277 	/// \param[in] argvpipe the list of arguments to pass through anonymous pipe
278 	/// \param[in] pool memory pool to use or nullptr for default memory allocation
279 	/// \note the command to execute must understand the --pipe-fd option that
280 	/// gives the filedescriptor to read from the command-line options
281     extern void tools_system_with_pipe(user_interaction & dialog,
282 				       const std::string & dar_cmd,
283 				       const std::vector<std::string> & argvpipe,
284 				       memory_pool *pool = nullptr);
285 
286 	/// write a list of string to file
287 
288 	/// \param[in] f the file to write to
289 	/// \param[in] x the list of string to write
290     extern void tools_write_vector(generic_file & f, const std::vector<std::string> & x);
291 
292 	/// read a list of string from a file
293 
294 	/// \param[in] f the file to read from
295 	/// \param[out] x the list to fill from file
296     extern void tools_read_vector(generic_file & f, std::vector<std::string> & x);
297 
298 	/// concatenate a vectors of strings in a single string
299 
300 	/// \param[in] separator string to insert between two elements
301 	/// \param[in] x the list string
302 	/// \return the result of the concatenation of the members of the list with separtor between two consecutive members
303     extern std::string tools_concat_vector(const std::string & separator,
304                                            const std::vector<std::string> & x);
305 
306 	/// concatenate two vectors
307 
308 	/// \param[in] a the first vector
309 	/// \param[in] b the second vector
310 	/// \return a vector containing the elements of a and the element of b
311     std::vector<std::string> operator + (std::vector<std::string> a, std::vector<std::string> b);
312 
313 
314 	/// display the compilation time features of libdar
315 
316 	/// \param[in,out] dialog for user interaction
317 	/// \note this call uses the compile_time:: routines, and will
318 	/// not change its interface upon new feature addition
319     extern void tools_display_features(user_interaction & dialog);
320 
321 
322 	/// test if two dates are equal taking care of a integer hour of difference
323 
324 	/// \param[in] hourshift is the number of integer hour more or less two date can be considered equal
325 	/// \param[in] date1 first date to compare
326 	/// \param[in] date2 second date to compare to
327 	/// \return whether dates are equal or not
328     extern bool tools_is_equal_with_hourshift(const infinint & hourshift, const datetime & date1, const datetime & date2);
329 
330 	/// template function to add two vectors
331 
operator +=(std::vector<T> & a,const std::vector<T> & b)332     template <class T> std::vector<T> operator +=(std::vector<T> & a, const std::vector<T> & b)
333     {
334         a = a + b;
335         return a;
336     }
337 
338 
339 	/// isolate the value of a given variable from the environment vector
340 
341 	/// \param[in] env the environment vector as retreived from the third argument of the main() function
342 	/// \param[in] clef the key or variable name too look for
343 	/// \return nullptr if the key could not be find or a pointer to the env data giving the value of the requested key
344 	/// \note the returned value must not be released by any mean as it is just a pointer to an system allocated memory (the env vector).
345     extern const char *tools_get_from_env(const char **env, const char *clef);
346 
347 	/// does sanity checks on a slice name, check presence and detect whether the given basename is not rather a filename
348 
349 	/// \param[in,out] dialog for user interaction
350 	/// \param[in] loc the path where resides the slice
351 	/// \param[in,out] base the basename of the slice
352 	/// \param[in] extension the extension of dar's slices
353 	/// \param[in] pool memory pool to use of nullptr for default memory allocation
354 	/// \note if user accepted the change of slice name proposed by libdar through dialog the base argument is changed
355     extern void tools_check_basename(user_interaction & dialog,
356                                      const path & loc,
357 				     std::string & base,
358 				     const std::string & extension,
359 				     memory_pool *pool = nullptr);
360 
361 	/// get current working directory
362 
363     extern std::string tools_getcwd();
364 
365 	/// returns the file pointed to by a symbolic link (or transparent if the file is not a symlink).
366 
367 	/// \param root the path to the file to read
368 	/// \return the file pointed to by the symlink or the value given in argument if it is not a symlink
369 	/// \note an exception can occur if lack of memory or invalid argument given (nullptr or empty string), system call error...
370     extern std::string tools_readlink(const char *root);
371 
372 	/// test the presence of an argument
373 
374 	/// \param[in] argument is the command line argument to look for
375 	/// \param[in] argc is the number of argument on the command line
376 	/// \param[in] argv is the list of argument on the command line
377 	/// \return true if the argument is present in the list
378 	/// \note THIS ROUTINE IS DEPRECATED AND WILL BE REMOVED IN A FUTURE VERSION OF LIBDAR
379     extern bool tools_look_for(const char *argument, S_I argc, char *const argv[]);
380 
381 
382 	/// set dates of a given file, no exception thrown
383 
384 	/// \param[in] chem the path to the file to set
385 	/// \param[in] symlink true if the file is a symlink
386 	/// \param[in] last_acc last access date to use
387 	/// \param[in] last_mod last modification date to use
388 	/// \param[in] birth creation date of the file, if not known, use the value of last_mod for efficiency
389     extern void tools_noexcept_make_date(const std::string & chem, bool symlink, const datetime & last_acc, const datetime & last_mod, const datetime & birth);
390 
391 	/// set dates of a given file, may throw exception
392 
393 	/// \param[in] chemin the path to the file to set
394 	/// \param[in] symlink true if the file is a symlink
395 	/// \param[in] access last access date to use
396 	/// \param[in] modif last modification date to use
397 	/// \param[in] birth time of creation of the file
398 	/// \note if birth time is not known, it should be set to the value of modif for efficiency
399     extern void tools_make_date(const std::string & chemin, bool symlink, const datetime & access, const datetime & modif, const datetime & birth);
400 
401 	/// compare two string in case insensitive manner
402 
403 	/// \param[in] a first string to compare
404 	/// \param[in] b second string to compare
405 	/// \return whether the two string given in argument are equal in case insensitive comparison
406     extern bool tools_is_case_insensitive_equal(const std::string & a, const std::string & b);
407 
408 	/// \brief convert a string to upper case
409 	///
410 	/// \param[in] r the string to convert
411 	/// \param[out] uppered resulting upper cased string
412 	/// \note in case of invalid wide char met in source string, the upper case convertion
413 	/// is done in ASCII mode (byte by byte)
414     extern void tools_to_upper(const std::string & r, std::string & uppered);
415 
416 #if HAVE_WCTYPE_H
417 	/// \brief convert a wstring to upper case
418 	///
419 	/// \param[in,out] r to convert
420 	/// \note wstring is a string of wchar_t (wide-char) type used to store
421 	/// on variable lenght of byte sequence the many characters defined with UTF
422 	/// like cirillic and greek letters.
423     extern void tools_to_wupper(std::wstring & r);
424 #endif
425 
426 	/// remove last character of a string is it equal to a given value
427 
428 	/// \param[in] c the given value to compare the last char with
429 	/// \param[in,out] s the string to modify
430     extern void tools_remove_last_char_if_equal_to(char c, std::string & s);
431 
432 	/// from a string with a range notation (min-max) extract the range values
433 
434 	/// \param[in] s the string to parse
435 	/// \param[out] min the minimum value of the range
436 	/// \param[out] max the maximum value of the range
437 	/// \exception Erange is thrown is the string to parse is incorrect
438 	/// \note: either a single number (positive or negative) is returned in min
439 	/// (max is set to min if min is positive or to zero if min is negative)
440 	/// or a range of positive numbers.
441     extern void tools_read_range(const std::string & s, S_I & min, U_I & max);
442 
443 
444 	/// make printf-like formating to a std::string
445 
446 	/// \param[in] format the format string
447 	/// \param[in] ... list of argument to use against the format string
448 	/// \return the resulting string
449 	/// \note the supported masks for the format are:
450 	/// - \%s \%c \%d \%\%  (usual behavior)
451 	/// - \%x display an integer under hexadecimal notation
452 	/// - \%i (matches infinint *)
453 	/// - \%S (matches std::string *)
454 	/// .
455     extern std::string tools_printf(const char *format, ...);
456 
457 	/// make printf-like formating to a std::string
458 
459 	/// \param[in] format the format string
460 	/// \param[in] ap list of argument to use against the format string
461 	/// \return the resulting string
462 	/// \note the supported masks for the format are:
463 	/// - \%s \%c \%d \%\%  (normal behavior)
464 	/// - \%i (matches infinint *)
465 	/// - \%S (matches std::string *)
466 	/// .
467     extern std::string tools_vprintf(const char *format, va_list ap);
468 
469 	/// test the presence of files corresponding to a given mask in a directory (regex mask)
470 
471 	/// \param[in,out] ui for user interaction
472 	/// \param[in] c_chemin directory where file have to be looked for
473 	/// \param[in] file_mask regex expression which designates the files to look for
474 	/// \return true if some files have found matching the file_mask
475     extern bool tools_do_some_files_match_mask_regex(user_interaction & ui, const std::string & c_chemin, const std::string & file_mask);
476 
477 
478 	/// remove files from a given directory
479 
480 	/// \param[in,out] dialog for user interaction
481 	/// \param[in] c_chemin directory where files have to be removed
482 	/// \param[in] file_mask regex expression which designates the files to remove
483 	/// \param[in] info_details whether user must be displayed details of the operation
484 	/// \note This is equivalent to the 'rm' command with regex expression in place of glob one
485     extern void tools_unlink_file_mask_regex(user_interaction & dialog, const std::string & c_chemin, const std::string & file_mask, bool info_details);
486 
487 
488 	/// prevents slice overwriting: check the presence of slice and if necessary ask the user if they can be removed
489 
490 	/// \param[in,out] dialog for user interaction
491 	/// \param[in] chemin where slice is about to be created
492 	/// \param[in] basename is the archive basename
493 	/// \param[in] extension is the archive filename extension
494 	/// \param[in] info_details whether user must be displayed details of the operation
495 	/// \param[in] allow_overwriting whether overwriting is allowed by the user
496 	/// \param[in] warn_overwriting whether a warning must be issued before overwriting (if allowed)
497 	/// \param[in] dry_run do a dry-run exection (no filesystem modification is performed)
498 	/// \note may thow exceptions.
499     extern void tools_avoid_slice_overwriting_regex(user_interaction & dialog,
500 						    const path & chemin,
501 						    const std::string & basename,
502 						    const std::string & extension,
503 						    bool info_details,
504 						    bool allow_overwriting,
505 						    bool warn_overwriting,
506 						    bool dry_run);
507 
508 	/// append an elastic buffer of given size to the file
509 
510 	/// \param[in,out] f file to append elastic buffer to
511 	/// \param[in] max_size size of the elastic buffer to add
512 	/// \param[in] modulo defines the size to choose (see note)
513 	/// \param[in] offset defines the offset to apply (see note)
514 	/// \note the size of the elastic buffer should not exceed max_size but
515 	/// should be chosen in order to reach a size which is zero modulo "modulo"
516 	/// assuming the offset we add the elastic buffer at is "offset". If modulo is zero
517 	/// this the elastic buffer is randomly chosen from 1 to max_size without any
518 	/// concern about being congruent to a given modulo.
519 	/// Example if module is 5 and offset is 2, the elastic buffer possible size
520 	/// can be 3 (2+3 is congruent to 0 modulo 5), 8 (2+8 is congruent to modulo 5), 12, etc.
521 	/// but not exceed max_size+modulo-1
522 	/// \note this is to accomodate the case when encrypted data is followed by clear data
523 	/// at the end of an archive. There is no way to known when we read clear data, but we
524 	/// know the clear data size is very inferior to crypted block size, thus when reading
525 	/// a uncompleted block of data we can be sure we have reached and of file and that
526 	/// the data is clear without any encrypted part because else we would have read an entire
527 	/// block of data.
528     extern void tools_add_elastic_buffer(generic_file & f,
529 					 U_32 max_size,
530 					 U_32 modulo,
531 					 U_32 offset);
532 
533 
534 	/// tells whether two files are on the same mounted filesystem
535 	///
536 	/// \param[in] file1 first file
537 	/// \param[in] file2 second file
538 	/// \return true if the two file are located under the same mounting point
539 	/// \note if one of the file is not present or if the filesystem information
540 	/// is not possible to be read an exception is throw (Erange)
541     extern bool tools_are_on_same_filesystem(const std::string & file1, const std::string & file2);
542 
543 
544 	/// transform a relative path to an absolute one given the current directory value
545 
546 	/// \param[in] src the relative path to transform
547 	/// \param[in] cwd the value to take for the current directory
548 	/// \return the corresponding absolute path
549     extern path tools_relative2absolute_path(const path & src, const path & cwd);
550 
551 	/// block all signals (based on POSIX sigprocmask)
552 
553 	/// \param[out] old_mask is set to the old mask value (for later unmasking signals)
554 	/// \exception Erange is thrown if system call failed for some reason
555     extern void tools_block_all_signals(sigset_t &old_mask);
556 
557 	/// unblock signals according to given mask
558 
559 	/// \param[in] old_mask value to set to blocked signal mask
560 	/// \exception Erange is thrown if system call failed for some reason
561     extern void tools_set_back_blocked_signals(sigset_t old_mask);
562 
563 	/// counts the number of a given char in a given string
564 
565 	/// \param[in] s string to look inside of
566 	/// \param[in] a char to look for
567 	/// \return the number of char found
568     extern U_I tools_count_in_string(const std::string & s, const char a);
569 
570 	/// returns the last modification date of the given file
571 
572 	/// \param[in,out] dialog for user interaction
573 	/// \param[in] s path of the file to get the last mtime
574 	/// \param[in] auto_zeroing whether to just warn instead of asking user confirmation
575 	/// \param[in] silent if set do not warn nor ask
576 	/// \return the mtime of the given file
577     extern datetime tools_get_mtime(user_interaction & dialog,
578 				    const std::string & s,
579 				    bool auto_zeroing,
580 				    bool silent);
581 
582 	/// returns the size of the given plain file
583 
584 	/// \param[in] s path of the file to get the size
585 	/// \return the size if the file in byte
586     extern infinint tools_get_size(const std::string & s);
587 
588 	/// returns the last change date of the given file
589 
590 	/// \param[in] s path of the file to get the last ctime
591 	/// \return the ctime of the given file
592     extern datetime tools_get_ctime(const std::string & s);
593 
594 	/// read a file and split its contents into words
595 
596 	/// \param[in,out] f is the file to read
597 	/// \return the list of words found in this order in the file
598 	/// \note The different quotes are taken into account
599     extern std::vector<std::string> tools_split_in_words(generic_file & f);
600 
601 
602 	/// read a std::string and split its contents into words
603 
604 	/// \param[in,out] arg is the string to read
605 	/// \return the list of words found in this order in the file
606 	/// \note The different quotes are taken into account
607     extern std::vector<std::string> tools_split_in_words(const std::string & arg);
608 
609 
610 	/// look next char in string out of parenthesis
611 
612 	/// \param[in] data is the string to look into
613 	/// \param[in] what is the char to look for
614 	/// \param[in] start is the index in string to start from, assuming at given position we are out of parenthesis
615 	/// \param[out] found the position of the next char equal to what
616 	/// \return true if a char equal to 'what' has been found and set the 'found' argument to its position or returns false if
617 	/// no such character has been found out of parenthesis
618 	/// \note the 'found' argument is assigned only if the call returns true, its value is not to be used when false is returned from the call
619 	/// \note second point, the start data should point to a character that is out of any parenthesis, behavior is undefined else.
620     extern bool tools_find_next_char_out_of_parenthesis(const std::string & data, const char what,  U_32 start, U_32 & found);
621 
622 
623 	/// produce the string resulting from the substition of % macro defined in the map
624 
625 	/// \param[in] hook is the user's expression in which to proceed to substitution
626 	/// \param[in] corres is a map telling which char following a % sign to replace by which string
627 	/// \return the resulting string of the substitution
628     extern std::string tools_substitute(const std::string & hook,
629 					const std::map<char, std::string> & corres);
630 
631 
632 	/// produces the string resulting from the substitution of %... macro
633 
634 	/// \param[in] hook the string in which to substitute
635 	/// \param[in] path is by what %p will be replaced
636 	/// \param[in] basename is by what %b will be replaced
637 	/// \param[in] num is by what %n will be replaced
638 	/// \param[in] padded_num is by what %N will be replaced
639 	/// \param[in] ext is by what %e will be replaced
640 	/// \param[in] context is by what %c will be replaced
641 	/// \return the substitued resulting string
642 	/// \note it now relies on tools_substitue
643     extern std::string tools_hook_substitute(const std::string & hook,
644 					     const std::string & path,
645 					     const std::string & basename,
646 					     const std::string & num,
647 					     const std::string & padded_num,
648 					     const std::string & ext,
649 					     const std::string & context);
650 
651 
652 	/// execute and retries at user will a given command line
653 
654 	/// \param[in] ui which way to ask the user whether to continue upon command line error
655 	/// \param[in] cmd_line the command line to execute
656     extern void tools_hook_execute(user_interaction & ui,
657 				   const std::string & cmd_line);
658 
659 
660 	/// subsititue and execute command line
661 
662 	/// \param[in,out] ui this is the way to contact the user
663 	/// \param[in] hook the string in which to substitute
664 	/// \param[in] path is by what %p will be replaced
665 	/// \param[in] basename is by what %b will be replaced
666 	/// \param[in] num is by what %n will be replaced
667 	/// \param[in] padded_num is by what %N will be replaced
668 	/// \param[in] ext is by what %e will be replaced
669 	/// \param[in] context is by what %c will be replaced
670     extern void tools_hook_substitute_and_execute(user_interaction & ui,
671 						  const std::string & hook,
672 						  const std::string & path,
673 						  const std::string & basename,
674 						  const std::string & num,
675 						  const std::string & padded_num,
676 						  const std::string & ext,
677 						  const std::string & context);
678 
679 	/// builds a regex from root directory and user provided regex to be applied to the relative path
680 
681 
682 	/// \param[in] prefix is the root portion of the path
683 	/// \param[in] relative_part is the user provided regex to be applied to the relative path
684 	/// \return the corresponding regex to be applied to full absolute path
685     extern std::string tools_build_regex_for_exclude_mask(const std::string & prefix,
686 							  const std::string & relative_part);
687 
688 	/// convert string for xml output
689 
690 	/// \note any < > & quote and double quote are replaced by adequate sequence for unicode
691 	/// \note second point, nothing is done here to replace system native strings to unicode
692     extern std::string tools_output2xml(const std::string & src);
693 
694 	/// convert octal string to integer
695 
696 	/// \param perm is a string representing a number in octal (string must have a leading zero)
697 	/// \return the corresponding value as an integer
698     extern U_I tools_octal2int(const std::string & perm);
699 
700 
701 	/// convert a number to a string corresponding to its octal representation
702 
703 	/// \param perm is the octal number
704 	/// \return the corresponding octal string
705     extern std::string tools_int2octal(const U_I & perm);
706 
707 	/// convert a permission number into its string representation (rwxrwxrwx)
708 
709     extern std::string tools_get_permission_string(char type, U_32 perm, bool hard);
710 
711 	/// change the permission of the file which descriptor is given
712 
713 	/// \param[in] fd file's descriptor
714 	/// \param[in] perm file permission to set the file to
715     extern void tools_set_permission(S_I fd, U_I perm);
716 
717 	/// obtain the permission of the file which descriptor is given
718 
719 	/// \param[in] fd file's descriptor
720 	/// \return permission of the given file
721 	/// \note in case of error exception may be thrown
722     extern U_I tools_get_permission(S_I fd);
723 
724 	/// change ownership of the file which descriptor is given
725 
726 	/// convert string user name or uid to numeric uid value
727 
728 	/// \param[in] user string username
729 	/// \return uid value
730     extern uid_t tools_ownership2uid(const std::string & user);
731 
732 	/// convert string group name or gid to numeric gid value
733 
734 	/// \param[in] group string username
735 	/// \return uid value
736     extern uid_t tools_ownership2gid(const std::string & group);
737 
738 	/// change ownership of the file which descriptor is given
739 
740 	/// \param[in] filedesc file's descriptor
741 	/// \param[in] slice_user the user to set the file to. For empty string, no attempts to change the user ownership is done
742 	/// \param[in] slice_group the group to set the file to. For empty string, no attempts to change the group ownership is done
743 	/// \note this call may throw Erange exception upon system error
744     extern void tools_set_ownership(S_I filedesc, const std::string & slice_user, const std::string & slice_group);
745 
746 	/// Produces in "dest" the XORed value of "dest" and "src"
747 
748 	/// \param[in,out] dest is the area where to write down the result
749 	/// \param[in] src points to vector or array of values to convert
750 	/// \param[in] n is the number of byte to convert from src to dest
751 	/// \note dest *must* be a valid pointer to an allocated memory area of at least n bytes
752     extern void tools_memxor(void *dest, const void *src, U_I n);
753 
754 	/// Produces a list of TLV from a constant type and a list of string
755 
756 	/// \param[in,out] dialog for user interaction
757 	/// \param[in] type is the type each TLV will have
758 	/// \param[in] data is the list of string to convert into a list of TLV
759 	/// \return a tlv_list object. Each TLV in the list correspond to a string in the given list
760     extern tlv_list tools_string2tlv_list(user_interaction & dialog, const U_16 & type, const std::vector<std::string> & data);
761 
762 
763 
764 	/// Extract from anonymous pipe a tlv_list
765 
766 	/// \param[in,out] dialog for user interaction
767 	/// \param[in] fd the filedescriptor for the anonymous pipe's read extremity
768 	/// \param[out] result the resulting tlv_list
769     extern void tools_read_from_pipe(user_interaction & dialog, S_I fd, tlv_list & result);
770 
771 
772 
773 	/// Produces a pseudo random number x, where 0 <= x < max
774 
775 	/// \param[in] max defines the range of the random number to return
776 	/// \return the returned value ranges from 0 (zero) up to max (= including max)
777     extern U_I tools_pseudo_random(U_I max);
778 
779 
780 	/// Template for the decomposition of any number in any base (decimal, octal, hexa, etc.)
781 
782 	/// \param[in] number is the number to decompose
783 	/// \param[in] base is the base to decompose the number into
784 	/// \return a vector of 'digit' int the specified base, the first beeing the less significative
785 	/// \note this template does not take care of the possibily existing optimized euclide division to speed up the operation
786 	/// like what exists for infinint. A specific overriden fonction for this type would be better.
787 	/// \note, the name "big_endian" is erroneous, it gives a little endian vector
788 
tools_number_base_decomposition_in_big_endian(N number,const B & base)789     template <class N, class B> std::vector<B> tools_number_base_decomposition_in_big_endian(N number, const B & base)
790     {
791 	std::vector<B> ret;
792 
793 	if(base <= 0)
794 	    throw Erange("tools_number_decoupe_in_big_endian", "base must be strictly positive");
795 
796 	while(number != 0)
797 	{
798 	    ret.push_back(number % base);
799 	    number /= base;
800 	}
801 
802 	return ret;
803     }
804 
805 	/// convert a unsigned char into its hexa decima representation
806 
807 	/// \param[in] x is the byte to convert
808 	/// \return the string representing the value of x written in hexadecimal
809     std::string tools_unsigned_char_to_hexa(unsigned char x);
810 
811 	/// convert a string into its hexadecima representation
812 
813 	/// \param[in] input input string to convert
814 	/// \return a string containing an hexadecimal number corresponding to the bytes of the input string
815 
816     std::string tools_string_to_hexa(const std::string & input);
817 
818 	/// Defines the CRC size to use for a given filesize
819 
820 	/// \param[in] size is the size of the file to protect by CRC
821 	/// \return crc_size is the size of the crc to use
822     extern infinint tools_file_size_to_crc_size(const infinint & size);
823 
824 	/// return a string containing the Effective UID
825     extern std::string tools_get_euid();
826 
827 	/// return a string containing the Effective UID
828     extern std::string tools_get_egid();
829 
830 	/// return a string containing the hostname of the current host
831     extern std::string tools_get_hostname();
832 
833 	/// return a string containing the current time (UTC)
834     extern std::string tools_get_date_utc();
835 
836 	/// return the string about compression ratio
837     extern std::string tools_get_compression_ratio(const infinint & storage_size, const infinint & file_size, bool compressed);
838 
839 	/// wrapper routine to strerror_r
840     extern std::string tools_strerror_r(int errnum);
841 
842 #ifdef GPGME_SUPPORT
843 	/// wrapper routint to gpgme_strerror_r
844     extern std::string tools_gpgme_strerror_r(gpgme_error_t err);
845 #endif
846 
847 #if HAVE_WCHAR_H
848 	/// convert a std::string to std::wstring (wide-string, aka string of wchar_t)
849     extern std::wstring tools_string_to_wstring(const std::string & val);
850 
851 	/// convert a std::wstring to std::string
852     extern std::string tools_wstring_to_string(const std::wstring & val);
853 #endif
854 
855 	/// add in 'a', element of 'b' not already found in 'a'
856     extern void tools_merge_to_vector(std::vector<std::string> & a, const  std::vector<std::string> & b);
857 
858 	/// remove from 'a' elements found in 'b' and return the resulting vector
859     extern std::vector<std::string> tools_substract_from_vector(const std::vector<std::string> & a, const std::vector<std::string> & b);
860 
861 	/// allocate a new dirent structure for use with readdir_r
862 	///
863 	/// \param[in] path_name is the path of to the directory (and its underlying filesystem)
864 	/// where the resulting dirent will be used. Depending on fileystem, the size of the dirent
865 	/// structure may vary it is necessary to know the directory where the corresponding files
866 	/// resides
867 	/// \param[in] pool whether to allocate the structure on a memory_pool or out of memory_pool
868 	/// \param[out] max_name_length is the maximum filename length allocated in the returned structure
869 	/// which succeeds when pool is set to nullptr
870 	/// \return a pointer to the newly allocated dirent structure
871     struct dirent *tools_allocate_struct_dirent(const std::string & path_name, U_64 & max_name_length, memory_pool *pool = nullptr);
872 
873 
874 	/// release a dirent structure as allocated by tools_allocate_struct_dirent
875 	///
876 	/// \param[in] ptr is the address of the structure to release
877     extern void tools_release_struct_dirent(struct dirent *ptr);
878 
879 	/// display the content of a secu_string, this function is only for trouble shooting!
880     extern void tools_secu_string_show(user_interaction & dialog, const std::string & msg, const secu_string & key);
881 
tools_max(T a,T b)882     template <class T> T tools_max(T a, T b) { return a > b ? a : b; }
tools_min(T a,T b)883     template <class T> T tools_min(T a, T b) { return a > b ? b : a; }
884 
885 	/// escape with a anti-slash character a set of chars found in the given string
886     extern std::string tools_escape_chars_in_string(const std::string & val, const char *to_escape);
887 
888 	/// convert an infinint to U_64 (aka "uint64_t" or yet "unsigned long long")
889 
890 	/// \note: if the infinint is too large to fit in an U_64 it returns false
891     extern bool tools_infinint2U_64(infinint val, U_64 & res);
892 
893 
894 	/// check the value is not negative, and if asked set it to zero
895 
896 	///\param[in,out] val variable which value to check
897 	///\param[in,out] ui for user interaction if necessary
898 	///\param[in] inode_path to the inode for message info
899 	///\param[in] nature type of the date/time (mtime,atime,ctime,birthtime,...)
900 	///\param[in] ask_before whether to just warn or ask user for confirmation
901 	///\param[in] silent if set, do not warn nor ask
tools_check_negative_date(T & val,user_interaction & ui,const char * inode_path,const char * nature,bool ask_before,bool silent)902     template <class T> void tools_check_negative_date(T & val,
903 						      user_interaction & ui,
904 						      const char *inode_path,
905 						      const char *nature,
906 						      bool ask_before,
907 						      bool silent)
908     {
909 	if(val < 0)
910 	{
911 	    if(!silent)
912 	    {
913 		std::string msg = tools_printf(gettext("Found negative date (%s) for inode %s ."),
914 					       nature,
915 				      inode_path);
916 		if(ask_before)
917 		    ui.pause(tools_printf(gettext("%S Can we read it as if it was zero (1st January 1970 at 00:00:00 UTC)?"),
918 					  &msg));
919 		else // just warn
920 		    ui.warning(msg + gettext("Considering date as if it was zero (Jan 1970)"));
921 	    }
922 
923 	    val = 0;
924 	}
925     }
926 
927 } /// end of namespace
928 
929 #endif
930