1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3 * Libbrasero-burn
4 * Copyright (C) Philippe Rouquier 2005-2009 <bonfire-app@wanadoo.fr>
5 *
6 * Libbrasero-burn is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * The Libbrasero-burn authors hereby grant permission for non-GPL compatible
12 * GStreamer plugins to be used and distributed together with GStreamer
13 * and Libbrasero-burn. This permission is above and beyond the permissions granted
14 * by the GPL license by which Libbrasero-burn is covered. If you modify this code
15 * you may extend this exception to your version of the code, but you are not
16 * obligated to do so. If you do not wish to do so, delete this exception
17 * statement from your version.
18 *
19 * Libbrasero-burn is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to:
26 * The Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor
28 * Boston, MA 02110-1301, USA.
29 */
30
31 #ifdef HAVE_CONFIG_H
32 # include <config.h>
33 #endif
34
35 #include <stdio.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <ctype.h>
39 #include <sys/param.h>
40
41 #include <glib.h>
42 #include <glib-object.h>
43 #include <glib/gi18n-lib.h>
44 #include <glib/gstdio.h>
45
46 #include <gmodule.h>
47
48 #include "scsi-device.h"
49 #include "brasero-plugin-registration.h"
50 #include "burn-job.h"
51
52 #include "brasero-tags.h"
53 #include "brasero-track-data.h"
54 #include "brasero-track-disc.h"
55
56 #include "burn-volume.h"
57 #include "brasero-drive.h"
58 #include "brasero-volume.h"
59
60 #include "burn-volume-read.h"
61
62
63 #define BRASERO_TYPE_CHECKSUM_FILES (brasero_checksum_files_get_type ())
64 #define BRASERO_CHECKSUM_FILES(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_CHECKSUM_FILES, BraseroChecksumFiles))
65 #define BRASERO_CHECKSUM_FILES_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), BRASERO_TYPE_CHECKSUM_FILES, BraseroChecksumFilesClass))
66 #define BRASERO_IS_CHECKSUM_FILES(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), BRASERO_TYPE_CHECKSUM_FILES))
67 #define BRASERO_IS_CHECKSUM_FILES_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), BRASERO_TYPE_CHECKSUM_FILES))
68 #define BRASERO_CHECKSUM_FILES_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BRASERO_TYPE_CHECKSUM_FILES, BraseroChecksumFilesClass))
69
70 BRASERO_PLUGIN_BOILERPLATE (BraseroChecksumFiles, brasero_checksum_files, BRASERO_TYPE_JOB, BraseroJob);
71
72 struct _BraseroChecksumFilesPrivate {
73 /* the path to read from when we check */
74 gchar *sums_path;
75 BraseroChecksumType checksum_type;
76
77 gint64 file_num;
78
79 /* the FILE to write to when we generate */
80 FILE *file;
81
82 /* this is for the thread and the end of it */
83 GThread *thread;
84 GMutex *mutex;
85 GCond *cond;
86 gint end_id;
87
88 guint cancel;
89 };
90 typedef struct _BraseroChecksumFilesPrivate BraseroChecksumFilesPrivate;
91
92 #define BRASERO_CHECKSUM_FILES_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_CHECKSUM_FILES, BraseroChecksumFilesPrivate))
93
94 #define BLOCK_SIZE 64
95
96 #define BRASERO_SCHEMA_CONFIG "org.gnome.brasero.config"
97 #define BRASERO_PROPS_CHECKSUM_FILES "checksum-files"
98
99 static BraseroJobClass *parent_class = NULL;
100
101 static BraseroBurnResult
brasero_checksum_files_get_file_checksum(BraseroChecksumFiles * self,GChecksumType type,const gchar * path,gchar ** checksum_string,GError ** error)102 brasero_checksum_files_get_file_checksum (BraseroChecksumFiles *self,
103 GChecksumType type,
104 const gchar *path,
105 gchar **checksum_string,
106 GError **error)
107 {
108 BraseroChecksumFilesPrivate *priv;
109 guchar buffer [BLOCK_SIZE];
110 GChecksum *checksum;
111 gint read_bytes;
112 FILE *file;
113
114 priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
115
116 file = fopen (path, "r");
117 if (!file) {
118 int errsv;
119 gchar *name = NULL;
120
121 /* If the file doesn't exist carry on with next */
122 if (errno == ENOENT)
123 return BRASERO_BURN_RETRY;
124
125 name = g_path_get_basename (path);
126
127 errsv = errno;
128 g_set_error (error,
129 BRASERO_BURN_ERROR,
130 BRASERO_BURN_ERROR_GENERAL,
131 _("File \"%s\" could not be opened (%s)"),
132 name,
133 g_strerror (errsv));
134 g_free (name);
135
136 return BRASERO_BURN_ERR;
137 }
138
139 checksum = g_checksum_new (type);
140
141 read_bytes = fread (buffer, 1, BLOCK_SIZE, file);
142 g_checksum_update (checksum, buffer, read_bytes);
143
144 while (read_bytes == BLOCK_SIZE) {
145 if (priv->cancel) {
146 fclose (file);
147 g_checksum_free (checksum);
148 return BRASERO_BURN_CANCEL;
149 }
150
151 read_bytes = fread (buffer, 1, BLOCK_SIZE, file);
152 g_checksum_update (checksum, buffer, read_bytes);
153 }
154
155 *checksum_string = g_strdup (g_checksum_get_string (checksum));
156 g_checksum_free (checksum);
157 fclose (file);
158
159 return BRASERO_BURN_OK;
160 }
161
162 static BraseroBurnResult
brasero_checksum_files_add_file_checksum(BraseroChecksumFiles * self,const gchar * path,GChecksumType checksum_type,const gchar * graft_path,GError ** error)163 brasero_checksum_files_add_file_checksum (BraseroChecksumFiles *self,
164 const gchar *path,
165 GChecksumType checksum_type,
166 const gchar *graft_path,
167 GError **error)
168 {
169 BraseroBurnResult result = BRASERO_BURN_OK;
170 BraseroChecksumFilesPrivate *priv;
171 gchar *checksum_string = NULL;
172 gint written;
173
174 priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
175
176 /* write to the file */
177 result = brasero_checksum_files_get_file_checksum (self,
178 checksum_type,
179 path,
180 &checksum_string,
181 error);
182 if (result != BRASERO_BURN_OK)
183 return BRASERO_BURN_ERR;
184
185 written = fwrite (checksum_string,
186 strlen (checksum_string),
187 1,
188 priv->file);
189 g_free (checksum_string);
190
191 if (written != 1) {
192 int errsv = errno;
193 g_set_error (error,
194 BRASERO_BURN_ERROR,
195 BRASERO_BURN_ERROR_GENERAL,
196 _("Data could not be written (%s)"),
197 g_strerror (errsv));
198
199 return BRASERO_BURN_ERR;
200 }
201
202 written = fwrite (" ",
203 2,
204 1,
205 priv->file);
206
207 /* NOTE: we remove the first "/" from path so the file can be
208 * used with md5sum at the root of the disc once mounted */
209 written = fwrite (graft_path + 1,
210 strlen (graft_path + 1),
211 1,
212 priv->file);
213
214 if (written != 1) {
215 int errsv = errno;
216 g_set_error (error,
217 BRASERO_BURN_ERROR,
218 BRASERO_BURN_ERROR_GENERAL,
219 _("Data could not be written (%s)"),
220 g_strerror (errsv));
221
222 return BRASERO_BURN_ERR;
223 }
224
225 written = fwrite ("\n",
226 1,
227 1,
228 priv->file);
229
230 return result;
231 }
232
233 static BraseroBurnResult
brasero_checksum_files_explore_directory(BraseroChecksumFiles * self,GChecksumType checksum_type,gint64 file_nb,const gchar * directory,const gchar * disc_path,GHashTable * excludedH,GError ** error)234 brasero_checksum_files_explore_directory (BraseroChecksumFiles *self,
235 GChecksumType checksum_type,
236 gint64 file_nb,
237 const gchar *directory,
238 const gchar *disc_path,
239 GHashTable *excludedH,
240 GError **error)
241 {
242 BraseroBurnResult result = BRASERO_BURN_OK;
243 BraseroChecksumFilesPrivate *priv;
244 const gchar *name;
245 GDir *dir;
246
247 priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
248
249 dir = g_dir_open (directory, 0, error);
250 if (!dir || *error)
251 return BRASERO_BURN_ERR;
252
253 while ((name = g_dir_read_name (dir))) {
254 gchar *path;
255 gchar *graft_path;
256
257 if (priv->cancel) {
258 result = BRASERO_BURN_CANCEL;
259 break;
260 }
261
262 path = g_build_path (G_DIR_SEPARATOR_S, directory, name, NULL);
263 if (g_hash_table_lookup (excludedH, path)) {
264 g_free (path);
265 continue;
266 }
267
268 graft_path = g_build_path (G_DIR_SEPARATOR_S, disc_path, name, NULL);
269 if (g_file_test (path, G_FILE_TEST_IS_DIR)) {
270 result = brasero_checksum_files_explore_directory (self,
271 checksum_type,
272 file_nb,
273 path,
274 graft_path,
275 excludedH,
276 error);
277 g_free (path);
278 g_free (graft_path);
279
280 if (result != BRASERO_BURN_OK)
281 break;
282
283 continue;
284 }
285
286 /* Only checksum regular files and avoid fifos, ... */
287 if (!g_file_test (path, G_FILE_TEST_IS_REGULAR)) {
288 g_free (path);
289 g_free (graft_path);
290 continue;
291 }
292
293 result = brasero_checksum_files_add_file_checksum (self,
294 path,
295 checksum_type,
296 graft_path,
297 error);
298 g_free (graft_path);
299 g_free (path);
300
301 if (result != BRASERO_BURN_OK)
302 break;
303
304 priv->file_num ++;
305 brasero_job_set_progress (BRASERO_JOB (self),
306 (gdouble) priv->file_num /
307 (gdouble) file_nb);
308 }
309 g_dir_close (dir);
310
311 /* NOTE: we don't care if the file is twice or more on the disc,
312 * that would be too much overhead/memory consumption for something
313 * that scarcely happens and that way each file can be checked later*/
314
315 return result;
316 }
317
318 static BraseroBurnResult
brasero_checksum_file_process_former_line(BraseroChecksumFiles * self,BraseroTrack * track,const gchar * line,GError ** error)319 brasero_checksum_file_process_former_line (BraseroChecksumFiles *self,
320 BraseroTrack *track,
321 const gchar *line,
322 GError **error)
323 {
324 guint i;
325 gchar *path;
326 GSList *grafts;
327 guint written_bytes;
328 BraseroChecksumFilesPrivate *priv;
329
330 priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
331
332 /* first skip the checksum string */
333 i = 0;
334 while (!isspace (line [i])) i ++;
335
336 /* skip white spaces */
337 while (isspace (line [i])) i ++;
338
339 /* get the path string */
340 path = g_strdup (line + i);
341
342 for (grafts = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (track)); grafts; grafts = grafts->next) {
343 BraseroGraftPt *graft;
344 guint len;
345
346 /* NOTE: graft->path + 1 is because in the checksum files on the
347 * disc there is not first "/" so if we want to compare ... */
348 graft = grafts->data;
349 if (!strcmp (graft->path + 1, path)) {
350 g_free (path);
351 return BRASERO_BURN_OK;
352 }
353
354 len = strlen (graft->path + 1);
355 if (!strncmp (graft->path + 1, path, len)
356 && path [len] == G_DIR_SEPARATOR) {
357 g_free (path);
358 return BRASERO_BURN_OK;
359 }
360 }
361
362 g_free (path);
363
364 /* write the whole line in the new file */
365 written_bytes = fwrite (line, 1, strlen (line), priv->file);
366 if (written_bytes != strlen (line)) {
367 g_set_error (error,
368 BRASERO_BURN_ERROR,
369 BRASERO_BURN_ERROR_GENERAL,
370 "%s",
371 g_strerror (errno));
372 return BRASERO_BURN_ERR;
373 }
374
375 if (!fwrite ("\n", 1, 1, priv->file)) {
376 g_set_error (error,
377 BRASERO_BURN_ERROR,
378 BRASERO_BURN_ERROR_GENERAL,
379 "%s",
380 g_strerror (errno));
381 return BRASERO_BURN_ERR;
382 }
383
384 return BRASERO_BURN_OK;
385 }
386
387 static BraseroBurnResult
brasero_checksum_files_merge_with_former_session(BraseroChecksumFiles * self,GError ** error)388 brasero_checksum_files_merge_with_former_session (BraseroChecksumFiles *self,
389 GError **error)
390 {
391 BraseroBurnFlag flags = BRASERO_BURN_FLAG_NONE;
392 BraseroChecksumFilesPrivate *priv;
393 BraseroDeviceHandle *dev_handle;
394 BraseroVolFileHandle *handle;
395 BraseroBurnResult result;
396 BraseroDrive *burner;
397 BraseroMedium *medium;
398 BraseroVolFile *file;
399 BraseroTrack *track;
400 gchar buffer [2048];
401 BraseroVolSrc *vol;
402 goffset start_block;
403 const gchar *device;
404
405 priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
406
407 /* Now we need to know if we're merging. If so, we need to merge the
408 * former checksum file with the new ones. */
409 brasero_job_get_flags (BRASERO_JOB (self), &flags);
410 if (!(flags & BRASERO_BURN_FLAG_MERGE))
411 return BRASERO_BURN_OK;
412
413 /* get the former file */
414 result = brasero_job_get_last_session_address (BRASERO_JOB (self), &start_block);
415 if (result != BRASERO_BURN_OK)
416 return result;
417
418 /* try every file and make sure they are of the same type */
419 medium = NULL;
420 brasero_job_get_medium (BRASERO_JOB (self), &medium);
421 burner = brasero_medium_get_drive (medium);
422 device = brasero_drive_get_device (burner);
423 dev_handle = brasero_device_handle_open (device, FALSE, NULL);
424 if (!dev_handle)
425 return BRASERO_BURN_ERR;
426
427 vol = brasero_volume_source_open_device_handle (dev_handle, error);
428 file = brasero_volume_get_file (vol,
429 "/"BRASERO_MD5_FILE,
430 start_block,
431 NULL);
432
433 if (!file) {
434 file = brasero_volume_get_file (vol,
435 "/"BRASERO_SHA1_FILE,
436 start_block,
437 NULL);
438 if (!file) {
439 file = brasero_volume_get_file (vol,
440 "/"BRASERO_SHA256_FILE,
441 start_block,
442 NULL);
443 if (!file) {
444 brasero_volume_source_close (vol);
445 BRASERO_JOB_LOG (self, "no checksum file found");
446 return BRASERO_BURN_OK;
447 }
448 else if (priv->checksum_type != BRASERO_CHECKSUM_SHA256_FILE) {
449 brasero_volume_source_close (vol);
450 BRASERO_JOB_LOG (self, "checksum type mismatch (%i against %i)",
451 priv->checksum_type,
452 BRASERO_CHECKSUM_SHA256_FILE);
453 return BRASERO_BURN_OK;
454 }
455 }
456 else if (priv->checksum_type != BRASERO_CHECKSUM_SHA1_FILE) {
457 BRASERO_JOB_LOG (self, "checksum type mismatch (%i against %i)",
458 priv->checksum_type,
459 BRASERO_CHECKSUM_SHA1_FILE);
460 brasero_volume_source_close (vol);
461 return BRASERO_BURN_OK;
462 }
463 }
464 else if (priv->checksum_type != BRASERO_CHECKSUM_MD5_FILE) {
465 brasero_volume_source_close (vol);
466 BRASERO_JOB_LOG (self, "checksum type mismatch (%i against %i)",
467 priv->checksum_type,
468 BRASERO_CHECKSUM_MD5_FILE);
469 return BRASERO_BURN_OK;
470 }
471
472 BRASERO_JOB_LOG (self, "Found file %p", file);
473 handle = brasero_volume_file_open (vol, file);
474 brasero_volume_source_close (vol);
475
476 if (!handle) {
477 BRASERO_JOB_LOG (self, "Failed to open file");
478 brasero_device_handle_close (dev_handle);
479 brasero_volume_file_free (file);
480 return BRASERO_BURN_ERR;
481 }
482
483 brasero_job_get_current_track (BRASERO_JOB (self), &track);
484
485 /* Now check the files that have been replaced; to do that check the
486 * paths of the new image whenever a read path from former file is a
487 * child of one of the new paths, then it must not be included. */
488 result = brasero_volume_file_read_line (handle, buffer, sizeof (buffer));
489 while (result == BRASERO_BURN_RETRY) {
490 if (priv->cancel) {
491 brasero_volume_file_close (handle);
492 brasero_volume_file_free (file);
493 brasero_device_handle_close (dev_handle);
494 return BRASERO_BURN_CANCEL;
495 }
496
497 result = brasero_checksum_file_process_former_line (self,
498 track,
499 buffer,
500 error);
501 if (result != BRASERO_BURN_OK) {
502 brasero_volume_file_close (handle);
503 brasero_volume_file_free (file);
504 brasero_device_handle_close (dev_handle);
505 return result;
506 }
507
508 result = brasero_volume_file_read_line (handle, buffer, sizeof (buffer));
509 }
510
511 result = brasero_checksum_file_process_former_line (self, track, buffer, error);
512 brasero_volume_file_close (handle);
513 brasero_volume_file_free (file);
514 brasero_device_handle_close (dev_handle);
515
516 return result;
517 }
518
519 static BraseroBurnResult
brasero_checksum_files_create_checksum(BraseroChecksumFiles * self,GError ** error)520 brasero_checksum_files_create_checksum (BraseroChecksumFiles *self,
521 GError **error)
522 {
523 GSList *iter;
524 guint64 file_nb;
525 BraseroTrack *track;
526 GSettings *settings;
527 GHashTable *excludedH;
528 GChecksumType gchecksum_type;
529 BraseroChecksumFilesPrivate *priv;
530 BraseroChecksumType checksum_type;
531 BraseroBurnResult result = BRASERO_BURN_OK;
532
533 priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
534
535 /* get the checksum type */
536 settings = g_settings_new (BRASERO_SCHEMA_CONFIG);
537 checksum_type = g_settings_get_int (settings, BRASERO_PROPS_CHECKSUM_FILES);
538 g_object_unref (settings);
539
540 if (checksum_type & BRASERO_CHECKSUM_MD5_FILE)
541 gchecksum_type = G_CHECKSUM_MD5;
542 else if (checksum_type & BRASERO_CHECKSUM_SHA1_FILE)
543 gchecksum_type = G_CHECKSUM_SHA1;
544 else if (checksum_type & BRASERO_CHECKSUM_SHA256_FILE)
545 gchecksum_type = G_CHECKSUM_SHA256;
546 else {
547 checksum_type = BRASERO_CHECKSUM_MD5_FILE;
548 gchecksum_type = G_CHECKSUM_MD5;
549 }
550
551 /* opens a file for the sums */
552 switch (gchecksum_type) {
553 case G_CHECKSUM_MD5:
554 priv->checksum_type = BRASERO_CHECKSUM_MD5_FILE;
555 result = brasero_job_get_tmp_file (BRASERO_JOB (self),
556 ".md5",
557 &priv->sums_path,
558 error);
559 break;
560 case G_CHECKSUM_SHA1:
561 priv->checksum_type = BRASERO_CHECKSUM_SHA1_FILE;
562 result = brasero_job_get_tmp_file (BRASERO_JOB (self),
563 ".sha1",
564 &priv->sums_path,
565 error);
566 break;
567 case G_CHECKSUM_SHA256:
568 priv->checksum_type = BRASERO_CHECKSUM_SHA256_FILE;
569 result = brasero_job_get_tmp_file (BRASERO_JOB (self),
570 ".sha256",
571 &priv->sums_path,
572 error);
573 break;
574 default:
575 result = BRASERO_BURN_CANCEL;
576 break;
577 }
578
579 if (result != BRASERO_BURN_OK || !priv->sums_path)
580 return result;
581
582 priv->file = fopen (priv->sums_path, "w");
583 if (!priv->file) {
584 int errsv = errno;
585
586 g_set_error (error,
587 BRASERO_BURN_ERROR,
588 BRASERO_BURN_ERROR_GENERAL,
589 _("File \"%s\" could not be opened (%s)"),
590 priv->sums_path,
591 g_strerror (errsv));
592
593 return BRASERO_BURN_ERR;
594 }
595
596 if (brasero_job_get_current_track (BRASERO_JOB (self), &track) != BRASERO_BURN_OK)
597 BRASERO_JOB_NOT_SUPPORTED (self);
598
599 /* we fill a hash table with all the files that are excluded globally */
600 excludedH = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
601 iter = brasero_track_data_get_excluded_list (BRASERO_TRACK_DATA (track));
602 for (; iter; iter = iter->next) {
603 gchar *uri;
604 gchar *path;
605
606 /* get the path */
607 uri = iter->data;
608 path = g_filename_from_uri (uri, NULL, NULL);
609
610 if (path)
611 g_hash_table_insert (excludedH, path, path);
612 }
613
614 /* it's now time to start reporting our progress */
615 brasero_job_set_current_action (BRASERO_JOB (self),
616 BRASERO_BURN_ACTION_CHECKSUM,
617 _("Creating checksum for image files"),
618 TRUE);
619
620 file_nb = -1;
621 priv->file_num = 0;
622 brasero_track_data_get_file_num (BRASERO_TRACK_DATA (track), &file_nb);
623 if (file_nb > 0)
624 brasero_job_start_progress (BRASERO_JOB (self), TRUE);
625 else
626 file_nb = -1;
627
628 iter = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (track));
629 for (; iter; iter = iter->next) {
630 BraseroGraftPt *graft;
631 gchar *graft_path;
632 gchar *path;
633
634 if (priv->cancel) {
635 result = BRASERO_BURN_CANCEL;
636 break;
637 }
638
639 graft = iter->data;
640 if (!graft->uri)
641 continue;
642
643 /* get the current and future paths */
644 /* FIXME: graft->uri can be path or URIs ... This should be
645 * fixed for graft points. */
646 if (!graft->uri)
647 path = NULL;
648 else if (graft->uri [0] == '/')
649 path = g_strdup (graft->uri);
650 else if (g_str_has_prefix (graft->uri, "file://"))
651 path = g_filename_from_uri (graft->uri, NULL, NULL);
652 else
653 path = NULL;
654
655 graft_path = graft->path;
656
657 if (g_file_test (path, G_FILE_TEST_IS_DIR))
658 result = brasero_checksum_files_explore_directory (self,
659 gchecksum_type,
660 file_nb,
661 path,
662 graft_path,
663 excludedH,
664 error);
665 else {
666 result = brasero_checksum_files_add_file_checksum (self,
667 path,
668 gchecksum_type,
669 graft_path,
670 error);
671 priv->file_num ++;
672 brasero_job_set_progress (BRASERO_JOB (self),
673 (gdouble) priv->file_num /
674 (gdouble) file_nb);
675 }
676
677 g_free (path);
678 if (result != BRASERO_BURN_OK)
679 break;
680 }
681
682 g_hash_table_destroy (excludedH);
683
684 if (result == BRASERO_BURN_OK)
685 result = brasero_checksum_files_merge_with_former_session (self, error);
686
687 /* that's finished we close the file */
688 fclose (priv->file);
689 priv->file = NULL;
690
691 return result;
692 }
693
694 static BraseroBurnResult
brasero_checksum_files_sum_on_disc_file(BraseroChecksumFiles * self,GChecksumType type,BraseroVolSrc * src,BraseroVolFile * file,gchar ** checksum_string,GError ** error)695 brasero_checksum_files_sum_on_disc_file (BraseroChecksumFiles *self,
696 GChecksumType type,
697 BraseroVolSrc *src,
698 BraseroVolFile *file,
699 gchar **checksum_string,
700 GError **error)
701 {
702 guchar buffer [64 * 2048];
703 BraseroChecksumFilesPrivate *priv;
704 BraseroVolFileHandle *handle;
705 GChecksum *checksum;
706 gint read_bytes;
707
708 priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
709
710 handle = brasero_volume_file_open_direct (src, file);
711 if (!handle)
712 return BRASERO_BURN_ERR;
713
714 checksum = g_checksum_new (type);
715
716 read_bytes = brasero_volume_file_read_direct (handle,
717 buffer,
718 64);
719 g_checksum_update (checksum, buffer, read_bytes);
720
721 while (read_bytes == sizeof (buffer)) {
722 if (priv->cancel) {
723 brasero_volume_file_close (handle);
724 return BRASERO_BURN_CANCEL;
725 }
726
727 read_bytes = brasero_volume_file_read_direct (handle,
728 buffer,
729 64);
730 g_checksum_update (checksum, buffer, read_bytes);
731 }
732
733 *checksum_string = g_strdup (g_checksum_get_string (checksum));
734 g_checksum_free (checksum);
735
736 brasero_volume_file_close (handle);
737
738 return BRASERO_BURN_OK;
739 }
740
741 static BraseroVolFile *
brasero_checksum_files_get_on_disc_checksum_type(BraseroChecksumFiles * self,BraseroVolSrc * vol,guint start_block)742 brasero_checksum_files_get_on_disc_checksum_type (BraseroChecksumFiles *self,
743 BraseroVolSrc *vol,
744 guint start_block)
745 {
746 BraseroVolFile *file;
747 BraseroChecksumFilesPrivate *priv;
748
749 priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
750
751
752 file = brasero_volume_get_file (vol,
753 "/"BRASERO_MD5_FILE,
754 start_block,
755 NULL);
756
757 if (!file) {
758 file = brasero_volume_get_file (vol,
759 "/"BRASERO_SHA1_FILE,
760 start_block,
761 NULL);
762 if (!file) {
763 file = brasero_volume_get_file (vol,
764 "/"BRASERO_SHA256_FILE,
765 start_block,
766 NULL);
767 if (!file || !(priv->checksum_type & (BRASERO_CHECKSUM_SHA256_FILE|BRASERO_CHECKSUM_DETECT))) {
768 BRASERO_JOB_LOG (self, "no checksum file found");
769 if (file)
770 brasero_volume_file_free (file);
771
772 return NULL;
773 }
774 priv->checksum_type = BRASERO_CHECKSUM_SHA256_FILE;
775 }
776 else if (priv->checksum_type & (BRASERO_CHECKSUM_SHA1_FILE|BRASERO_CHECKSUM_DETECT))
777 priv->checksum_type = BRASERO_CHECKSUM_SHA1_FILE;
778 else {
779 brasero_volume_file_free (file);
780 file = NULL;
781 }
782 }
783 else if (priv->checksum_type & (BRASERO_CHECKSUM_MD5_FILE|BRASERO_CHECKSUM_DETECT))
784 priv->checksum_type = BRASERO_CHECKSUM_MD5_FILE;
785 else {
786 brasero_volume_file_free (file);
787 file = NULL;
788 }
789
790 BRASERO_JOB_LOG (self, "Found file %p", file);
791 return file;
792 }
793
794 static gint
brasero_checksum_files_get_line_num(BraseroChecksumFiles * self,BraseroVolFileHandle * handle)795 brasero_checksum_files_get_line_num (BraseroChecksumFiles *self,
796 BraseroVolFileHandle *handle)
797 {
798 BraseroBurnResult result;
799 int num = 0;
800
801 while ((result = brasero_volume_file_read_line (handle, NULL, 0)) == BRASERO_BURN_RETRY)
802 num ++;
803
804 if (result == BRASERO_BURN_ERR)
805 return -1;
806
807 brasero_volume_file_rewind (handle);
808 return num;
809 }
810
811 static BraseroBurnResult
brasero_checksum_files_check_files(BraseroChecksumFiles * self,GError ** error)812 brasero_checksum_files_check_files (BraseroChecksumFiles *self,
813 GError **error)
814 {
815 GValue *value;
816 guint file_nb;
817 guint file_num;
818 gint checksum_len;
819 BraseroVolSrc *vol;
820 goffset start_block;
821 BraseroTrack *track;
822 const gchar *device;
823 BraseroVolFile *file;
824 BraseroDrive *drive;
825 BraseroMedium *medium;
826 GChecksumType gchecksum_type;
827 GArray *wrong_checksums = NULL;
828 BraseroDeviceHandle *dev_handle;
829 BraseroChecksumFilesPrivate *priv;
830 BraseroVolFileHandle *handle = NULL;
831 BraseroBurnResult result = BRASERO_BURN_OK;
832
833 priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
834
835 /* get medium */
836 brasero_job_get_current_track (BRASERO_JOB (self), &track);
837 drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
838 medium = brasero_drive_get_medium (drive);
839
840 /* open volume */
841 if (!brasero_medium_get_last_data_track_address (medium, NULL, &start_block))
842 return BRASERO_BURN_ERR;
843
844 device = brasero_drive_get_device (brasero_medium_get_drive (medium));
845 dev_handle = brasero_device_handle_open (device, FALSE, NULL);
846 if (!dev_handle)
847 return BRASERO_BURN_ERROR;
848
849 vol = brasero_volume_source_open_device_handle (dev_handle, error);
850
851 /* open checksum file */
852 file = brasero_checksum_files_get_on_disc_checksum_type (self,
853 vol,
854 start_block);
855 if (!file) {
856 g_set_error (error,
857 BRASERO_BURN_ERROR,
858 BRASERO_BURN_ERROR_GENERAL,
859 _("No checksum file could be found on the disc"));
860
861 BRASERO_JOB_LOG (self, "No checksum file");
862 result = BRASERO_BURN_ERR;
863 goto end;
864 }
865
866 handle = brasero_volume_file_open (vol, file);
867 if (!handle) {
868 BRASERO_JOB_LOG (self, "Cannot open checksum file");
869 /* FIXME: error here ? */
870 result = BRASERO_BURN_ERR;
871 goto end;
872 }
873
874 /* get the number of files at this time and rewind */
875 file_nb = brasero_checksum_files_get_line_num (self, handle);
876 if (file_nb == 0) {
877 BRASERO_JOB_LOG (self, "Empty checksum file");
878 result = BRASERO_BURN_OK;
879 goto end;
880 }
881
882 if (file_nb < 0) {
883 /* An error here */
884 BRASERO_JOB_LOG (self, "Failed to retrieve the number of lines");
885 result = BRASERO_BURN_ERR;
886 goto end;
887 }
888
889 /* signal we're ready to start */
890 file_num = 0;
891 brasero_job_set_current_action (BRASERO_JOB (self),
892 BRASERO_BURN_ACTION_CHECKSUM,
893 _("Checking file integrity"),
894 TRUE);
895 brasero_job_start_progress (BRASERO_JOB (self), FALSE);
896
897 /* Get the checksum type */
898 switch (priv->checksum_type) {
899 case BRASERO_CHECKSUM_MD5_FILE:
900 gchecksum_type = G_CHECKSUM_MD5;
901 break;
902 case BRASERO_CHECKSUM_SHA1_FILE:
903 gchecksum_type = G_CHECKSUM_SHA1;
904 break;
905 case BRASERO_CHECKSUM_SHA256_FILE:
906 gchecksum_type = G_CHECKSUM_SHA256;
907 break;
908 default:
909 gchecksum_type = G_CHECKSUM_MD5;
910 break;
911 }
912
913 checksum_len = g_checksum_type_get_length (gchecksum_type) * 2;
914 while (1) {
915 gchar file_path [MAXPATHLEN + 1];
916 gchar checksum_file [512 + 1];
917 BraseroVolFile *disc_file;
918 gchar *checksum_real;
919 gint read_bytes;
920
921 if (priv->cancel)
922 break;
923
924 /* first read the checksum */
925 read_bytes = brasero_volume_file_read (handle,
926 checksum_file,
927 checksum_len);
928 if (read_bytes == 0)
929 break;
930
931 if (read_bytes != checksum_len) {
932 /* FIXME: an error here */
933 BRASERO_JOB_LOG (self, "Impossible to read the checksum from file");
934 result = BRASERO_BURN_ERR;
935 break;
936 }
937 checksum_file [checksum_len] = '\0';
938
939 if (priv->cancel)
940 break;
941
942 /* skip spaces in between */
943 while (1) {
944 gchar c [2];
945
946 read_bytes = brasero_volume_file_read (handle, c, 1);
947 if (read_bytes == 0) {
948 result = BRASERO_BURN_OK;
949 goto end;
950 }
951
952 if (read_bytes < 0) {
953 /* FIXME: an error here */
954 BRASERO_JOB_LOG (self, "Impossible to read checksum file");
955 result = BRASERO_BURN_ERR;
956 goto end;
957 }
958
959 if (!isspace (c [0])) {
960 file_path [0] = '/';
961 file_path [1] = c [0];
962 break;
963 }
964 }
965
966 /* get the filename */
967 result = brasero_volume_file_read_line (handle, file_path + 2, sizeof (file_path) - 2);
968
969 /* FIXME: an error here */
970 if (result == BRASERO_BURN_ERR) {
971 BRASERO_JOB_LOG (self, "Impossible to read checksum file");
972 break;
973 }
974
975 checksum_real = NULL;
976
977 /* get the file handle itself */
978 BRASERO_JOB_LOG (self, "Getting file %s", file_path);
979 disc_file = brasero_volume_get_file (vol,
980 file_path,
981 start_block,
982 NULL);
983 if (!disc_file) {
984 g_set_error (error,
985 BRASERO_BURN_ERROR,
986 BRASERO_BURN_ERROR_GENERAL,
987 _("File \"%s\" could not be opened"),
988 file_path);
989 result = BRASERO_BURN_ERR;
990 break;
991 }
992
993 /* we certainly don't want to checksum anything but regular file
994 * if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
995 * brasero_volume_file_free (disc_file);
996 * continue;
997 * }
998 */
999
1000 /* checksum the file */
1001 result = brasero_checksum_files_sum_on_disc_file (self,
1002 gchecksum_type,
1003 vol,
1004 disc_file,
1005 &checksum_real,
1006 error);
1007 brasero_volume_file_free (disc_file);
1008 if (result == BRASERO_BURN_ERR) {
1009 g_set_error (error,
1010 BRASERO_BURN_ERROR,
1011 BRASERO_BURN_ERROR_GENERAL,
1012 _("File \"%s\" could not be opened"),
1013 file_path);
1014 break;
1015 }
1016
1017 if (result != BRASERO_BURN_OK)
1018 break;
1019
1020 file_num++;
1021 brasero_job_set_progress (BRASERO_JOB (self),
1022 (gdouble) file_num /
1023 (gdouble) file_nb);
1024 BRASERO_JOB_LOG (self,
1025 "comparing checksums for file %s : %s (from md5 file) / %s (current)",
1026 file_path, checksum_file, checksum_real);
1027
1028 if (strcmp (checksum_file, checksum_real)) {
1029 gchar *string;
1030
1031 BRASERO_JOB_LOG (self, "Wrong checksum");
1032 if (!wrong_checksums)
1033 wrong_checksums = g_array_new (TRUE,
1034 TRUE,
1035 sizeof (gchar *));
1036
1037 string = g_strdup (file_path);
1038 wrong_checksums = g_array_append_val (wrong_checksums, string);
1039 }
1040
1041 g_free (checksum_real);
1042 if (priv->cancel)
1043 break;
1044 }
1045
1046 end:
1047
1048 if (handle)
1049 brasero_volume_file_close (handle);
1050
1051 if (file)
1052 brasero_volume_file_free (file);
1053
1054 if (vol)
1055 brasero_volume_source_close (vol);
1056
1057 if (dev_handle)
1058 brasero_device_handle_close (dev_handle);
1059
1060 if (result != BRASERO_BURN_OK) {
1061 BRASERO_JOB_LOG (self, "Ended with an error");
1062 if (wrong_checksums) {
1063 g_strfreev ((gchar **) wrong_checksums->data);
1064 g_array_free (wrong_checksums, FALSE);
1065 }
1066 return result;
1067 }
1068
1069 if (!wrong_checksums)
1070 return BRASERO_BURN_OK;
1071
1072 /* add the tag */
1073 value = g_new0 (GValue, 1);
1074 g_value_init (value, G_TYPE_STRV);
1075 g_value_take_boxed (value, wrong_checksums->data);
1076 g_array_free (wrong_checksums, FALSE);
1077
1078 brasero_track_tag_add (track,
1079 BRASERO_TRACK_MEDIUM_WRONG_CHECKSUM_TAG,
1080 value);
1081
1082 g_set_error (error,
1083 BRASERO_BURN_ERROR,
1084 BRASERO_BURN_ERROR_BAD_CHECKSUM,
1085 _("Some files may be corrupted on the disc"));
1086
1087 return BRASERO_BURN_ERR;
1088 }
1089
1090 struct _BraseroChecksumFilesThreadCtx {
1091 BraseroChecksumFiles *sum;
1092 BraseroBurnResult result;
1093 GError *error;
1094 };
1095 typedef struct _BraseroChecksumFilesThreadCtx BraseroChecksumFilesThreadCtx;
1096
1097 static gboolean
brasero_checksum_files_end(gpointer data)1098 brasero_checksum_files_end (gpointer data)
1099 {
1100 BraseroJobAction action;
1101 BraseroChecksumFiles *self;
1102 BraseroTrack *current = NULL;
1103 BraseroChecksumFilesPrivate *priv;
1104 BraseroChecksumFilesThreadCtx *ctx;
1105
1106 ctx = data;
1107 self = ctx->sum;
1108 priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
1109
1110 /* NOTE ctx/data is destroyed in its own callback */
1111 priv->end_id = 0;
1112
1113 if (ctx->result != BRASERO_BURN_OK) {
1114 GError *error;
1115
1116 error = ctx->error;
1117 ctx->error = NULL;
1118
1119 brasero_job_error (BRASERO_JOB (self), error);
1120 return FALSE;
1121 }
1122
1123 brasero_job_get_action (BRASERO_JOB (self), &action);
1124 if (action == BRASERO_JOB_ACTION_CHECKSUM) {
1125 /* everything was done in thread */
1126 brasero_job_finished_track (BRASERO_JOB (self));
1127 return FALSE;
1128 }
1129
1130 /* we were asked to create a checksum. Its type depends on the input */
1131 brasero_job_get_current_track (BRASERO_JOB (self), ¤t);
1132
1133 /* let's create a new DATA track with the md5 file created */
1134 if (BRASERO_IS_TRACK_DATA (current)) {
1135 GSList *iter;
1136 GSList *grafts;
1137 GSList *excluded;
1138 BraseroGraftPt *graft;
1139 GSList *new_grafts = NULL;
1140 BraseroTrackData *track = NULL;
1141
1142 /* for DATA track we add the file to the track */
1143 grafts = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (current));
1144 for (; grafts; grafts = grafts->next) {
1145 graft = grafts->data;
1146 graft = brasero_graft_point_copy (graft);
1147 new_grafts = g_slist_prepend (new_grafts, graft);
1148 }
1149
1150 graft = g_new0 (BraseroGraftPt, 1);
1151 graft->uri = g_strconcat ("file://", priv->sums_path, NULL);
1152 switch (priv->checksum_type) {
1153 case BRASERO_CHECKSUM_SHA1_FILE:
1154 graft->path = g_strdup ("/"BRASERO_SHA1_FILE);
1155 break;
1156 case BRASERO_CHECKSUM_SHA256_FILE:
1157 graft->path = g_strdup ("/"BRASERO_SHA256_FILE);
1158 break;
1159 case BRASERO_CHECKSUM_MD5_FILE:
1160 default:
1161 graft->path = g_strdup ("/"BRASERO_MD5_FILE);
1162 break;
1163 }
1164
1165 BRASERO_JOB_LOG (self,
1166 "Adding graft for checksum file %s %s",
1167 graft->path,
1168 graft->uri);
1169
1170 new_grafts = g_slist_prepend (new_grafts, graft);
1171 excluded = brasero_track_data_get_excluded_list (BRASERO_TRACK_DATA (current));
1172
1173 /* Duplicate the list since brasero_track_data_set_source ()
1174 * takes ownership afterwards */
1175 excluded = g_slist_copy (excluded);
1176 for (iter = excluded; iter; iter = iter->next)
1177 iter->data = g_strdup (iter->data);
1178
1179 track = brasero_track_data_new ();
1180 brasero_track_data_add_fs (track, brasero_track_data_get_fs (BRASERO_TRACK_DATA (current)));
1181 brasero_track_data_set_source (track, new_grafts, excluded);
1182 brasero_track_set_checksum (BRASERO_TRACK (track),
1183 priv->checksum_type,
1184 graft->uri);
1185
1186 brasero_job_add_track (BRASERO_JOB (self), BRASERO_TRACK (track));
1187
1188 /* It's good practice to unref the track afterwards as we don't
1189 * need it anymore. BraseroTaskCtx refs it. */
1190 g_object_unref (track);
1191
1192 brasero_job_finished_track (BRASERO_JOB (self));
1193 return FALSE;
1194 }
1195 else
1196 goto error;
1197
1198 return FALSE;
1199
1200 error:
1201 {
1202 GError *error = NULL;
1203
1204 error = g_error_new (BRASERO_BURN_ERROR,
1205 BRASERO_BURN_ERROR_BAD_CHECKSUM,
1206 _("Some files may be corrupted on the disc"));
1207 brasero_job_error (BRASERO_JOB (self), error);
1208 return FALSE;
1209 }
1210 }
1211
1212 static void
brasero_checksum_files_destroy(gpointer data)1213 brasero_checksum_files_destroy (gpointer data)
1214 {
1215 BraseroChecksumFilesThreadCtx *ctx;
1216
1217 ctx = data;
1218 if (ctx->error) {
1219 g_error_free (ctx->error);
1220 ctx->error = NULL;
1221 }
1222
1223 g_free (ctx);
1224 }
1225
1226 static gpointer
brasero_checksum_files_thread(gpointer data)1227 brasero_checksum_files_thread (gpointer data)
1228 {
1229 GError *error = NULL;
1230 BraseroJobAction action;
1231 BraseroChecksumFiles *self;
1232 BraseroTrack *current = NULL;
1233 BraseroChecksumFilesPrivate *priv;
1234 BraseroChecksumFilesThreadCtx *ctx;
1235 BraseroBurnResult result = BRASERO_BURN_NOT_SUPPORTED;
1236
1237 self = BRASERO_CHECKSUM_FILES (data);
1238 priv = BRASERO_CHECKSUM_FILES_PRIVATE (self);
1239
1240 /* check DISC types and add checksums for DATA and IMAGE-bin types */
1241 brasero_job_get_action (BRASERO_JOB (self), &action);
1242 brasero_job_get_current_track (BRASERO_JOB (self), ¤t);
1243 if (action == BRASERO_JOB_ACTION_CHECKSUM) {
1244 priv->checksum_type = brasero_track_get_checksum_type (current);
1245 if (priv->checksum_type & (BRASERO_CHECKSUM_MD5_FILE|BRASERO_CHECKSUM_SHA1_FILE|BRASERO_CHECKSUM_SHA256_FILE|BRASERO_CHECKSUM_DETECT))
1246 result = brasero_checksum_files_check_files (self, &error);
1247 else
1248 result = BRASERO_BURN_ERR;
1249 }
1250 else if (action == BRASERO_JOB_ACTION_IMAGE) {
1251 if (BRASERO_IS_TRACK_DATA (current))
1252 result = brasero_checksum_files_create_checksum (self, &error);
1253 else
1254 result = BRASERO_BURN_ERR;
1255 }
1256
1257 if (result != BRASERO_BURN_CANCEL) {
1258 ctx = g_new0 (BraseroChecksumFilesThreadCtx, 1);
1259 ctx->sum = self;
1260 ctx->error = error;
1261 ctx->result = result;
1262 priv->end_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1263 brasero_checksum_files_end,
1264 ctx,
1265 brasero_checksum_files_destroy);
1266 }
1267
1268 /* End thread */
1269 g_mutex_lock (priv->mutex);
1270 priv->thread = NULL;
1271 g_cond_signal (priv->cond);
1272 g_mutex_unlock (priv->mutex);
1273
1274 g_thread_exit (NULL);
1275 return NULL;
1276 }
1277
1278 static BraseroBurnResult
brasero_checksum_files_start(BraseroJob * job,GError ** error)1279 brasero_checksum_files_start (BraseroJob *job,
1280 GError **error)
1281 {
1282 BraseroChecksumFilesPrivate *priv;
1283 GError *thread_error = NULL;
1284 BraseroJobAction action;
1285
1286 brasero_job_get_action (job, &action);
1287 if (action == BRASERO_JOB_ACTION_SIZE) {
1288 /* say we won't write to disc */
1289 brasero_job_set_output_size_for_current_track (job, 0, 0);
1290 return BRASERO_BURN_NOT_RUNNING;
1291 }
1292
1293 /* we start a thread for the exploration of the graft points */
1294 priv = BRASERO_CHECKSUM_FILES_PRIVATE (job);
1295 g_mutex_lock (priv->mutex);
1296 priv->thread = g_thread_create (brasero_checksum_files_thread,
1297 BRASERO_CHECKSUM_FILES (job),
1298 FALSE,
1299 &thread_error);
1300 g_mutex_unlock (priv->mutex);
1301
1302 /* Reminder: this is not necessarily an error as the thread may have finished */
1303 //if (!priv->thread)
1304 // return BRASERO_BURN_ERR;
1305 if (thread_error) {
1306 g_propagate_error (error, thread_error);
1307 return BRASERO_BURN_ERR;
1308 }
1309
1310 return BRASERO_BURN_OK;
1311 }
1312
1313 static BraseroBurnResult
brasero_checksum_files_activate(BraseroJob * job,GError ** error)1314 brasero_checksum_files_activate (BraseroJob *job,
1315 GError **error)
1316 {
1317 GSList *grafts;
1318 BraseroTrack *track = NULL;
1319 BraseroTrackType *output = NULL;
1320
1321 output = brasero_track_type_new ();
1322 brasero_job_get_output_type (job, output);
1323
1324 if (!brasero_track_type_get_has_data (output)) {
1325 brasero_track_type_free (output);
1326 return BRASERO_BURN_OK;
1327 }
1328
1329 brasero_track_type_free (output);
1330
1331 /* see that a file with graft "/BRASERO_CHECKSUM_FILE" doesn't already
1332 * exists (possible when doing several copies) or when a simulation
1333 * already took place before. */
1334 brasero_job_get_current_track (job, &track);
1335 grafts = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (track));
1336 for (; grafts; grafts = grafts->next) {
1337 BraseroGraftPt *graft;
1338
1339 graft = grafts->data;
1340 if (graft->path) {
1341 if (!strcmp (graft->path, "/"BRASERO_MD5_FILE))
1342 return BRASERO_BURN_NOT_RUNNING;
1343 if (!strcmp (graft->path, "/"BRASERO_SHA1_FILE))
1344 return BRASERO_BURN_NOT_RUNNING;
1345 if (!strcmp (graft->path, "/"BRASERO_SHA256_FILE))
1346 return BRASERO_BURN_NOT_RUNNING;
1347 }
1348 }
1349
1350 return BRASERO_BURN_OK;
1351 }
1352
1353 static BraseroBurnResult
brasero_checksum_files_stop(BraseroJob * job,GError ** error)1354 brasero_checksum_files_stop (BraseroJob *job,
1355 GError **error)
1356 {
1357 BraseroChecksumFilesPrivate *priv;
1358
1359 priv = BRASERO_CHECKSUM_FILES_PRIVATE (job);
1360
1361 g_mutex_lock (priv->mutex);
1362 if (priv->thread) {
1363 priv->cancel = 1;
1364 g_cond_wait (priv->cond, priv->mutex);
1365 priv->cancel = 0;
1366 priv->thread = NULL;
1367 }
1368 g_mutex_unlock (priv->mutex);
1369
1370 if (priv->end_id) {
1371 g_source_remove (priv->end_id);
1372 priv->end_id = 0;
1373 }
1374
1375 if (priv->file) {
1376 fclose (priv->file);
1377 priv->file = NULL;
1378 }
1379
1380 if (priv->sums_path) {
1381 g_free (priv->sums_path);
1382 priv->sums_path = NULL;
1383 }
1384
1385 return BRASERO_BURN_OK;
1386 }
1387
1388 static void
brasero_checksum_files_init(BraseroChecksumFiles * obj)1389 brasero_checksum_files_init (BraseroChecksumFiles *obj)
1390 {
1391 BraseroChecksumFilesPrivate *priv;
1392
1393 priv = BRASERO_CHECKSUM_FILES_PRIVATE (obj);
1394
1395 priv->mutex = g_mutex_new ();
1396 priv->cond = g_cond_new ();
1397 }
1398
1399 static void
brasero_checksum_files_finalize(GObject * object)1400 brasero_checksum_files_finalize (GObject *object)
1401 {
1402 BraseroChecksumFilesPrivate *priv;
1403
1404 priv = BRASERO_CHECKSUM_FILES_PRIVATE (object);
1405
1406 g_mutex_lock (priv->mutex);
1407 if (priv->thread) {
1408 priv->cancel = 1;
1409 g_cond_wait (priv->cond, priv->mutex);
1410 priv->cancel = 0;
1411 priv->thread = NULL;
1412 }
1413 g_mutex_unlock (priv->mutex);
1414
1415 if (priv->end_id) {
1416 g_source_remove (priv->end_id);
1417 priv->end_id = 0;
1418 }
1419
1420 if (priv->file) {
1421 fclose (priv->file);
1422 priv->file = NULL;
1423 }
1424
1425 if (priv->mutex) {
1426 g_mutex_free (priv->mutex);
1427 priv->mutex = NULL;
1428 }
1429
1430 if (priv->cond) {
1431 g_cond_free (priv->cond);
1432 priv->cond = NULL;
1433 }
1434
1435 G_OBJECT_CLASS (parent_class)->finalize (object);
1436 }
1437
1438 static void
brasero_checksum_files_class_init(BraseroChecksumFilesClass * klass)1439 brasero_checksum_files_class_init (BraseroChecksumFilesClass *klass)
1440 {
1441 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1442 BraseroJobClass *job_class = BRASERO_JOB_CLASS (klass);
1443
1444 g_type_class_add_private (klass, sizeof (BraseroChecksumFilesPrivate));
1445
1446 parent_class = g_type_class_peek_parent (klass);
1447 object_class->finalize = brasero_checksum_files_finalize;
1448
1449 job_class->activate = brasero_checksum_files_activate;
1450 job_class->start = brasero_checksum_files_start;
1451 job_class->stop = brasero_checksum_files_stop;
1452 }
1453
1454 static void
brasero_checksum_files_export_caps(BraseroPlugin * plugin)1455 brasero_checksum_files_export_caps (BraseroPlugin *plugin)
1456 {
1457 GSList *input;
1458 BraseroPluginConfOption *checksum_type;
1459
1460 brasero_plugin_define (plugin,
1461 "file-checksum",
1462 /* Translators: this is the name of the plugin
1463 * which will be translated only when it needs
1464 * displaying. */
1465 N_("File Checksum"),
1466 _("Checks file integrities on a disc"),
1467 "Philippe Rouquier",
1468 0);
1469
1470 /* only generate a file for DATA input */
1471 input = brasero_caps_data_new (BRASERO_IMAGE_FS_ANY);
1472 brasero_plugin_process_caps (plugin, input);
1473 g_slist_free (input);
1474
1475 /* run on initial track for whatever a DATA track */
1476 brasero_plugin_set_process_flags (plugin, BRASERO_PLUGIN_RUN_PREPROCESSING);
1477
1478 /* For discs, we can only check each files on a disc against an md5sum
1479 * file (provided we managed to mount the disc).
1480 * NOTE: we can't generate md5 from discs anymore. There are too many
1481 * problems reading straight from the disc dev. So we use readcd or
1482 * equivalent instead */
1483 input = brasero_caps_disc_new (BRASERO_MEDIUM_CD|
1484 BRASERO_MEDIUM_DVD|
1485 BRASERO_MEDIUM_DUAL_L|
1486 BRASERO_MEDIUM_PLUS|
1487 BRASERO_MEDIUM_RESTRICTED|
1488 BRASERO_MEDIUM_SEQUENTIAL|
1489 BRASERO_MEDIUM_WRITABLE|
1490 BRASERO_MEDIUM_REWRITABLE|
1491 BRASERO_MEDIUM_CLOSED|
1492 BRASERO_MEDIUM_APPENDABLE|
1493 BRASERO_MEDIUM_HAS_DATA);
1494 brasero_plugin_check_caps (plugin,
1495 BRASERO_CHECKSUM_DETECT|
1496 BRASERO_CHECKSUM_MD5_FILE|
1497 BRASERO_CHECKSUM_SHA1_FILE|
1498 BRASERO_CHECKSUM_SHA256_FILE,
1499 input);
1500 g_slist_free (input);
1501
1502 /* add some configure options */
1503 checksum_type = brasero_plugin_conf_option_new (BRASERO_PROPS_CHECKSUM_FILES,
1504 _("Hashing algorithm to be used:"),
1505 BRASERO_PLUGIN_OPTION_CHOICE);
1506 brasero_plugin_conf_option_choice_add (checksum_type,
1507 _("MD5"), BRASERO_CHECKSUM_MD5_FILE);
1508 brasero_plugin_conf_option_choice_add (checksum_type,
1509 _("SHA1"), BRASERO_CHECKSUM_SHA1_FILE);
1510 brasero_plugin_conf_option_choice_add (checksum_type,
1511 _("SHA256"), BRASERO_CHECKSUM_SHA256_FILE);
1512
1513 brasero_plugin_add_conf_option (plugin, checksum_type);
1514
1515 brasero_plugin_set_compulsory (plugin, FALSE);
1516 }
1517