Line data Source code
1 : /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 : /*
3 : * files.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 files.c
25 : * This file contains the functions to deal with files of the "Sauvegarde"
26 : * collection programs.
27 : */
28 :
29 : #include "libcdpfgl.h"
30 :
31 :
32 : /**
33 : * @returns a newly allocated meta_data_t * empty structure. We use 65534
34 : * as default uid and gid to avoid using 0 which is dedicated to a
35 : * priviledged user.
36 : */
37 101698 : meta_data_t *new_meta_data_t(void)
38 : {
39 101698 : meta_data_t *meta = NULL;
40 :
41 101698 : meta = (meta_data_t *) g_malloc(sizeof(meta_data_t));
42 :
43 101698 : if (meta != NULL)
44 : {
45 101698 : meta->file_type = 0;
46 101698 : meta->inode = 0;
47 101698 : meta->mode = 0;
48 101698 : meta->atime = 0;
49 101698 : meta->ctime = 0;
50 101698 : meta->mtime = 0;
51 101698 : meta->size = 0;
52 101698 : meta->owner = NULL;
53 101698 : meta->group = NULL;
54 101698 : meta->uid = 65534; /* nfsnobody on my system ie unpriviledged user */
55 101698 : meta->gid = 65534; /* nfsnobody on my system ie unpriviledged user */
56 101698 : meta->name = NULL;
57 101698 : meta->link = NULL;
58 101698 : meta->hash_data_list = NULL;
59 101698 : meta->in_cache = FALSE; /* a newly meta data is not in the local cache ! */
60 101698 : meta->blocksize = 16384; /* Default blocksize */
61 : }
62 :
63 101698 : return meta;
64 : }
65 :
66 :
67 : /**
68 : * @returns a newly allocated server_meta_data_t * empty structure.
69 : */
70 49926 : server_meta_data_t *new_smeta_data_t(void)
71 : {
72 49926 : server_meta_data_t *smeta = NULL;
73 :
74 49926 : smeta = (server_meta_data_t *) g_malloc(sizeof(server_meta_data_t));
75 :
76 49926 : if (smeta != NULL)
77 : {
78 49926 : smeta->hostname = NULL;
79 49926 : smeta->data_sent = FALSE;
80 49926 : smeta->meta = NULL;
81 : }
82 :
83 49926 : return smeta;
84 : }
85 :
86 :
87 : /**
88 : * Frees the meta_data_t * structure
89 : * @param meta is a meta_data_t * structure to be freed
90 : * @param free_link is a boolean that when set to TRUE will free
91 : * @returns always NULL
92 : */
93 101698 : gpointer free_meta_data_t(meta_data_t *meta, gboolean free_link)
94 : {
95 101698 : if (meta != NULL)
96 : {
97 101698 : free_variable(meta->owner);
98 101698 : free_variable(meta->group);
99 101698 : free_variable(meta->name);
100 :
101 101698 : if (free_link == TRUE)
102 : {
103 : /* meta->link should not be freed only in 'client' program */
104 49926 : free_variable(meta->link);
105 : }
106 :
107 101698 : g_list_free_full(meta->hash_data_list, free_hdt_struct);
108 101698 : free_variable(meta);
109 : }
110 :
111 101698 : return NULL;
112 : }
113 :
114 :
115 : /**
116 : * Frees the server_meta_data_t * structure
117 : * @param smeta is a meta_data_t * structure to be freed
118 : * @returns always NULL
119 : */
120 49926 : gpointer free_smeta_data_t(server_meta_data_t *smeta)
121 : {
122 49926 : if (smeta != NULL)
123 : {
124 49926 : smeta->meta = free_meta_data_t(smeta->meta, TRUE);
125 49926 : smeta->hostname = free_variable(smeta->hostname);
126 49926 : smeta = free_variable(smeta);
127 : }
128 :
129 49926 : return NULL;
130 : }
131 :
132 :
133 : /**
134 : * Wrapper for the g_slist_free_full function
135 : * the pointer to the data to be freed
136 : * @param the pointer to the data to be freed by free_smeta_data_t call.
137 : */
138 7 : void gslist_free_smeta(gpointer data)
139 : {
140 7 : free_smeta_data_t((server_meta_data_t *)data);
141 7 : }
142 :
143 :
144 : /**
145 : * Gets the filename of a GFile
146 : * @param a_file : the GFile to get the filename from.
147 : * @returns the name of the GFile if any or "--" gchar * string that may be
148 : * freed when no longer needed
149 : */
150 0 : gchar *get_filename_from_gfile(GFile *a_file)
151 : {
152 0 : gchar *filename = NULL;
153 :
154 0 : if (a_file != NULL)
155 : {
156 0 : filename = g_file_get_parse_name(a_file);
157 : }
158 :
159 0 : return filename;
160 : }
161 :
162 :
163 : /**
164 : * Returns the inode of the file fileinfo
165 : * @param fileinfo : a GFileInfo pointer obtained from an opened file
166 : * (GFile *)
167 : * @param[out] meta : meta_data_t * structure that contains all meta data
168 : * for the corresponding file (populated here with
169 : * inode number.
170 : * @returns the inode file.
171 : */
172 0 : guint64 get_inode_from_gfile(GFileInfo *fileinfo, meta_data_t *meta)
173 : {
174 0 : guint64 inode = 0;
175 :
176 :
177 0 : if (fileinfo != NULL && meta != NULL)
178 : {
179 0 : inode = g_file_info_get_attribute_uint64(fileinfo, G_FILE_ATTRIBUTE_UNIX_INODE);
180 :
181 0 : meta->inode = inode;
182 : }
183 :
184 0 : return inode;
185 : }
186 :
187 :
188 : /**
189 : * Returns the username of the owner of the file fileinfo
190 : * @param fileinfo : a GFileInfo pointer obtained from an opened file
191 : * (GFile *)
192 : * @param[out] meta : meta_data_t * structure that contains all meta data
193 : * for the corresponding file (populated here with owner,
194 : * group, uid and gid.
195 : * @returns the "user:group uid:gid" of the file or an empty string if an
196 : * error occurs
197 : */
198 0 : gchar *get_username_owner_from_gfile(GFileInfo *fileinfo, meta_data_t *meta)
199 : {
200 0 : gchar *result = NULL;
201 :
202 0 : if (fileinfo != NULL && meta != NULL)
203 : {
204 :
205 :
206 0 : meta->owner = g_file_info_get_attribute_as_string(fileinfo, G_FILE_ATTRIBUTE_OWNER_USER);
207 0 : meta->group = g_file_info_get_attribute_as_string(fileinfo, G_FILE_ATTRIBUTE_OWNER_GROUP);
208 :
209 0 : meta->uid = g_file_info_get_attribute_uint32(fileinfo, G_FILE_ATTRIBUTE_UNIX_UID);
210 0 : meta->gid = g_file_info_get_attribute_uint32(fileinfo, G_FILE_ATTRIBUTE_UNIX_GID);
211 :
212 0 : result = g_strdup_printf("%s:%s %d:%d", meta->owner, meta->group, meta->uid, meta->gid);
213 : }
214 : else
215 : {
216 0 : result = g_strdup("");
217 : }
218 :
219 0 : return result;
220 : }
221 :
222 :
223 : /**
224 : * Returns the dates of a file
225 : * @param fileinfo : a GFileInfo pointer obtained from an opened file
226 : * (GFile *)
227 : * @param meta : meta_data_t * structure that contains all meta data for
228 : * the corresponding file.
229 : * @returns "access_time changed_time modified_time" gchar *string
230 : */
231 0 : gchar *get_dates_from_gfile(GFileInfo *fileinfo, meta_data_t *meta)
232 : {
233 0 : gchar *result = NULL;
234 :
235 0 : if (fileinfo != NULL && meta != NULL)
236 : {
237 0 : meta->atime = g_file_info_get_attribute_uint64(fileinfo, G_FILE_ATTRIBUTE_TIME_ACCESS);
238 0 : meta->ctime = g_file_info_get_attribute_uint64(fileinfo, G_FILE_ATTRIBUTE_TIME_CHANGED);
239 0 : meta->mtime = g_file_info_get_attribute_uint64(fileinfo, G_FILE_ATTRIBUTE_TIME_MODIFIED);
240 :
241 0 : result = g_strdup_printf("%" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT "", meta->atime, meta->ctime, meta->mtime);
242 : }
243 : else
244 : {
245 0 : result = g_strdup("");
246 : }
247 :
248 0 : return result;
249 : }
250 :
251 :
252 : /**
253 : * sets the dates to a file
254 : * @param fileinfo : a GFileInfo pointer obtained from an opened file
255 : * (GFile *)
256 : * @param meta : meta_data_t * structure that contains all meta data for
257 : * to set to the corresponding file.
258 : */
259 4 : void set_dates_to_gfile(GFileInfo *fileinfo, meta_data_t *meta)
260 : {
261 4 : if (fileinfo != NULL && meta != NULL)
262 : {
263 4 : g_file_info_set_attribute_uint64(fileinfo, G_FILE_ATTRIBUTE_TIME_ACCESS, meta->atime);
264 4 : g_file_info_set_attribute_uint64(fileinfo, G_FILE_ATTRIBUTE_TIME_CHANGED, meta->ctime);
265 4 : g_file_info_set_attribute_uint64(fileinfo, G_FILE_ATTRIBUTE_TIME_MODIFIED, meta->mtime);
266 : }
267 4 : }
268 :
269 :
270 : /**
271 : * Get unix mode of a file
272 : * @param fileinfo : a GFileInfo pointer obtained from an opened file
273 : * (GFile *)
274 : * @param meta : meta_data_t * structure that contains all meta data for
275 : * the corresponding file.
276 : * @returns a newly allocated string with file mode in decimal
277 : * representation.
278 : */
279 0 : gchar *get_file_mode_from_gfile(GFileInfo *fileinfo, meta_data_t *meta)
280 : {
281 0 : gchar *result = NULL;
282 :
283 0 : if (fileinfo != NULL)
284 : {
285 0 : meta->mode = g_file_info_get_attribute_uint32(fileinfo, G_FILE_ATTRIBUTE_UNIX_MODE);
286 :
287 0 : result = g_strdup_printf("%d", meta->mode);
288 : }
289 : else
290 : {
291 0 : result = g_strdup("");
292 : }
293 :
294 0 : return result;
295 : }
296 :
297 :
298 : /**
299 : * Set unix mode of a file
300 : * @param fileinfo : a GFileInfo pointer obtained from an opened file
301 : * (GFile *)
302 : * @param meta : meta_data_t * structure that contains all meta data for
303 : * the corresponding file.
304 : */
305 4 : void set_file_mode_to_gfile(GFileInfo *fileinfo, meta_data_t *meta)
306 : {
307 4 : if (fileinfo != NULL && meta != NULL)
308 : {
309 4 : print_debug(_("Setting mode: %d\n"), meta->mode);
310 4 : g_file_info_set_attribute_uint32(fileinfo, G_FILE_ATTRIBUTE_UNIX_MODE, meta->mode);
311 : }
312 4 : }
313 :
314 :
315 : /**
316 : * Gets the size of a file
317 : * @param fileinfo : a GFileInfo pointer obtained from an opened file
318 : * (GFile *)
319 : * @param meta : meta_data_t * structure that contains all meta data for
320 : * the corresponding file.
321 : * @returns a newly allocated string with file size in decimal
322 : * representation.
323 : */
324 0 : gchar *get_file_size_from_gfile(GFileInfo *fileinfo, meta_data_t *meta)
325 : {
326 0 : gchar *result = NULL;
327 :
328 0 : if (fileinfo != NULL)
329 : {
330 0 : meta->size = g_file_info_get_attribute_uint64(fileinfo, G_FILE_ATTRIBUTE_STANDARD_SIZE);
331 :
332 0 : result = g_strdup_printf("%" G_GUINT64_FORMAT "", meta->size);
333 : }
334 : else
335 : {
336 0 : result = g_strdup("");
337 : }
338 :
339 0 : return result;
340 : }
341 :
342 :
343 : /**
344 : * Returns the file size from a GFile * file
345 : * @param file is the GFile from which we want the size.
346 : * @returns a guint64 that represents the file size or 0.
347 : */
348 0 : guint64 get_file_size(GFile *file)
349 : {
350 0 : GError *error = NULL;
351 0 : GFileInfo *fileinfo = NULL;
352 0 : guint64 size = 0;
353 :
354 0 : if (file != NULL)
355 : {
356 0 : fileinfo = g_file_query_info(file, "*", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &error);
357 0 : size = g_file_info_get_attribute_uint64(fileinfo, G_FILE_ATTRIBUTE_STANDARD_SIZE);
358 0 : free_object(fileinfo);
359 : }
360 :
361 0 : return size;
362 : }
363 :
364 :
365 : /**
366 : * Checks if a filename exists or not.
367 : * @param filename that we want to check.
368 : * @returns TRUE if filename exists and FALSE if not.
369 : */
370 6 : gboolean file_exists(gchar *filename)
371 : {
372 6 : GFile *file = NULL;
373 6 : gboolean exists = FALSE;
374 :
375 6 : if (filename != NULL)
376 : {
377 6 : file = g_file_new_for_path(filename);
378 6 : exists = g_file_query_exists(file, NULL);
379 6 : free_object(file);
380 : }
381 :
382 6 : return exists;
383 : }
384 :
385 :
386 : /**
387 : * Comparison function to be used when sorting filenames. First filenames
388 : * are compared and when an equality is found then the modified time is
389 : * compared (as a second sorting criteria)
390 : * @param a server_meta_data_t * representing a file 'a'
391 : * @param b server_meta_data_t * representing a file 'b' to be compared
392 : * with 'a'
393 : * @returns a negative integer if the a comes before b, 0 if they are
394 : * equal, or a positive integer if the a comes after b.
395 : */
396 709 : gint compare_filenames(gconstpointer a, gconstpointer b)
397 : {
398 709 : gchar *key_a = NULL;
399 709 : gchar *key_b = NULL;
400 709 : gint value = 0;
401 709 : server_meta_data_t *sa = (server_meta_data_t *) a;
402 709 : server_meta_data_t *sb = (server_meta_data_t *) b;
403 :
404 :
405 709 : key_a = g_utf8_collate_key_for_filename(sa->meta->name, -1);
406 709 : key_b = g_utf8_collate_key_for_filename(sb->meta->name, -1);
407 :
408 709 : value = strcmp(key_a, key_b);
409 :
410 709 : if (value == 0)
411 : { /* second sorting criteria : modification time */
412 14 : if (sa->meta->mtime < sb->meta->mtime)
413 : {
414 : value = -1;
415 : }
416 14 : else if (sa->meta->mtime > sb->meta->mtime)
417 : {
418 : value = 1;
419 : }
420 : else
421 : {
422 0 : value = 0;
423 : }
424 : }
425 :
426 709 : free_variable(key_a);
427 709 : free_variable(key_b);
428 :
429 709 : return value;
430 : }
431 :
432 :
433 : /**
434 : * Prints a file ands its meta data to the screen
435 : * @param smeta is the server meta data of the file to be printed on the
436 : * screen
437 : */
438 174 : void print_smeta_to_screen(server_meta_data_t *smeta)
439 : {
440 174 : meta_data_t *meta = NULL; /**< helper to access smeta->meta structure do not free ! */
441 174 : GDateTime *la_date = NULL;
442 174 : gchar *the_date = NULL;
443 :
444 174 : if (smeta != NULL && smeta->meta != NULL)
445 : {
446 174 : meta = smeta->meta;
447 :
448 174 : switch (meta->file_type)
449 : {
450 : case 1:
451 165 : fprintf(stdout, "[FILE] ");
452 165 : break;
453 : case 2:
454 9 : fprintf(stdout, "[DIR ] ");
455 9 : break;
456 : case 3:
457 0 : fprintf(stdout, "[LINK] ");
458 0 : break;
459 : default:
460 0 : fprintf(stdout, "[ ] ");
461 0 : break;
462 : }
463 :
464 174 : la_date = g_date_time_new_from_unix_local(meta->mtime);
465 174 : the_date = g_date_time_format(la_date, "%F %T %z");
466 :
467 174 : fprintf(stdout, "%s ", the_date);
468 :
469 174 : fprintf(stdout, "%s\n", meta->name);
470 :
471 174 : free_variable(the_date);
472 174 : g_date_time_unref(la_date);
473 : }
474 :
475 174 : }
476 :
477 :
478 : /**
479 : * Sets file attributes
480 : * @param file is a GFile pointer and must not be null
481 : * @param meta is the structure that contains all meta data for the
482 : * file that we want to set.
483 : */
484 4 : void set_file_attributes(GFile *file, meta_data_t *meta)
485 : {
486 4 : GError *error = NULL;
487 4 : GFileInfo *fileinfo = NULL;
488 :
489 4 : if (file != NULL && meta != NULL)
490 : {
491 4 : fileinfo = g_file_query_info(file, "*", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &error);
492 :
493 4 : if (fileinfo == NULL || error != NULL)
494 : {
495 0 : print_error(__FILE__, __LINE__, _("Error while getting file information: %s\n"), error->message);
496 0 : error = free_error(error);
497 : }
498 : else
499 : {
500 4 : set_file_mode_to_gfile(fileinfo, meta);
501 4 : set_dates_to_gfile(fileinfo, meta);
502 :
503 4 : if (g_file_set_attributes_from_info(file, fileinfo, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &error) == FALSE && error != NULL)
504 : {
505 4 : print_error(__FILE__, __LINE__, _("Error or warning for file (%s): %s\n"), meta->name, error->message);
506 4 : free_error(error);
507 : }
508 :
509 4 : free_object(fileinfo);
510 : }
511 : }
512 : else
513 : {
514 : /* To translators : do not translate this ! */
515 0 : print_error(__FILE__, __LINE__, "set_file_attribute(file = %p, meta = %p)\n", file, meta);
516 : }
517 4 : }
518 :
519 :
520 : /**
521 : * Makes a symbolic link named with 'file' filename that points to the
522 : * target 'points_to'
523 : * @param file is the file to create as a symbolic link
524 : * @param points_to is the target of the link
525 : */
526 0 : void make_symbolic_link(GFile *file, gchar *points_to)
527 : {
528 0 : gchar *filename = NULL;
529 0 : GError *error = NULL;
530 :
531 0 : if (file != NULL && points_to != NULL)
532 : {
533 0 : if (g_file_make_symbolic_link(file, points_to, NULL, &error) == FALSE && error != NULL)
534 : {
535 0 : filename = g_file_get_path(file);
536 0 : print_error(__FILE__, __LINE__, _("Error: unable to create symbolic link %s to %s: %s.\n"), filename, points_to, error->message);
537 0 : free_variable(filename);
538 : }
539 : }
540 0 : }
541 :
542 :
543 : /**
544 : * Replaces ~ (if found at the first place) by the home directory
545 : * of the user.
546 : * @param path is a gchar * string that should contain a path
547 : * @returns always returns a newly allocated gchar * string that contains
548 : * the normalized path or the path itself;
549 : */
550 10 : gchar *normalize_directory(gchar *path)
551 : {
552 10 : gchar *dircache = NULL;
553 :
554 10 : if (path != NULL && path[0] == '~')
555 : {
556 0 : dircache = g_strconcat(g_get_home_dir(), path+1, NULL);
557 : }
558 : else
559 : {
560 10 : dircache = g_strdup(path);
561 : }
562 :
563 10 : return dircache;
564 : }
|