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), &current);
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), &current);
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