1
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
4
* Copyright (C) Philippe Rouquier 2005-2009 <bonfire-app@wanadoo.fr>
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.
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.
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.
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.
36
#include <glib-object.h>
37
#include <glib/gi18n-lib.h>
38
#include <glib/gstdio.h>
44
#include "brasero-units.h"
46
#include "brasero-plugin-registration.h"
49
#include "brasero-track.h"
50
#include "brasero-track-data.h"
51
#include "brasero-track-image.h"
53
BRASERO_PLUGIN_BOILERPLATE (BraseroBurnURI, brasero_burn_uri, BRASERO_TYPE_JOB, BraseroJob);
55
struct _BraseroBurnURIPrivate {
67
typedef struct _BraseroBurnURIPrivate BraseroBurnURIPrivate;
69
#define BRASERO_BURN_URI_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_BURN_URI, BraseroBurnURIPrivate))
71
static GObjectClass *parent_class = NULL;
75
brasero_burn_uri_thread_finished (BraseroBurnURI *self)
77
BraseroBurnURIPrivate *priv;
79
priv = BRASERO_BURN_URI_PRIVATE (self);
84
g_object_unref (priv->cancel);
86
if (g_cancellable_is_cancelled (priv->cancel))
95
brasero_job_error (BRASERO_JOB (self), error);
99
brasero_job_add_track (BRASERO_JOB (self), priv->track);
100
brasero_job_finished_track (BRASERO_JOB (self));
106
brasero_burn_uri_find_graft (gconstpointer A, gconstpointer B)
108
const BraseroGraftPt *graft = A;
110
if (graft && graft->path)
111
return strcmp (graft->path, B);
117
brasero_burn_uri_explore_directory (BraseroBurnURI *self,
121
GCancellable *cancel,
124
BraseroTrack *current = NULL;
125
GFileEnumerator *enumerator;
126
GSList *current_grafts;
129
enumerator = g_file_enumerate_children (file,
130
G_FILE_ATTRIBUTE_STANDARD_NAME ","
131
G_FILE_ATTRIBUTE_STANDARD_TYPE ","
132
"burn::backing-file",
133
G_FILE_QUERY_INFO_NONE,
138
g_slist_foreach (grafts, (GFunc) brasero_graft_point_free, NULL);
139
g_slist_free (grafts);
143
brasero_job_get_current_track (BRASERO_JOB (self), ¤t);
144
current_grafts = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (current));
146
while ((info = g_file_enumerator_next_file (enumerator, cancel, error))) {
147
if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
150
BraseroGraftPt *graft;
152
/* Make sure it's not one of the original grafts */
153
/* we need to know if that's a directory or not since if
154
* it is then mkisofs (but not genisoimage) requires the
155
* disc path to end with '/'; if there isn't '/' at the
156
* end then only the directory contents are added. */
157
disc_path = g_build_filename (path, g_file_info_get_name (info), G_DIR_SEPARATOR_S, NULL);
158
if (g_slist_find_custom (current_grafts, disc_path, (GCompareFunc) brasero_burn_uri_find_graft)) {
159
BRASERO_JOB_LOG (self, "Graft already in list %s", disc_path);
160
g_object_unref (info);
165
/* we need a dummy directory */
166
graft = g_new0 (BraseroGraftPt, 1);
168
graft->path = disc_path;
169
grafts = g_slist_prepend (grafts, graft);
171
BRASERO_JOB_LOG (self, "Adding directory %s at %s", graft->uri, graft->path);
173
directory = g_file_get_child (file, g_file_info_get_name (info));
174
grafts = brasero_burn_uri_explore_directory (self,
180
g_object_unref (directory);
183
g_object_unref (info);
184
g_object_unref (enumerator);
188
else if (g_file_info_get_file_type (info) == G_FILE_TYPE_REGULAR
189
/* NOTE: burn:// URI allows symlink */
190
|| g_file_info_get_file_type (info) == G_FILE_TYPE_SYMBOLIC_LINK) {
191
const gchar *real_path;
192
BraseroGraftPt *graft;
195
real_path = g_file_info_get_attribute_byte_string (info, "burn::backing-file");
199
BRASERO_BURN_ERROR_GENERAL,
200
_("Impossible to retrieve local file path"));
202
g_slist_foreach (grafts, (GFunc) brasero_graft_point_free, NULL);
203
g_slist_free (grafts);
204
g_object_unref (info);
205
g_object_unref (file);
209
/* Make sure it's not one of the original grafts */
210
disc_path = g_build_filename (path, g_file_info_get_name (info), NULL);
211
if (g_slist_find_custom (current_grafts, disc_path, (GCompareFunc) brasero_burn_uri_find_graft)) {
212
BRASERO_JOB_LOG (self, "Graft already in list %s", disc_path);
213
g_object_unref (info);
218
graft = g_new0 (BraseroGraftPt, 1);
219
graft->path = disc_path;
220
graft->uri = g_strdup (real_path);
221
/* FIXME: maybe one day, graft->uri will always be an URI */
222
/* graft->uri = g_filename_to_uri (real_path, NULL, NULL); */
224
/* Make sure it's not one of the original grafts */
226
grafts = g_slist_prepend (grafts, graft);
228
BRASERO_JOB_LOG (self, "Added file %s at %s", graft->uri, graft->path);
231
g_object_unref (info);
233
g_object_unref (enumerator);
239
brasero_burn_uri_retrieve_path (BraseroBurnURI *self,
245
BraseroBurnURIPrivate *priv;
247
priv = BRASERO_BURN_URI_PRIVATE (self);
252
file = g_file_new_for_uri (uri);
253
info = g_file_query_info (file,
254
G_FILE_ATTRIBUTE_STANDARD_NAME ","
255
G_FILE_ATTRIBUTE_STANDARD_TYPE ","
256
"burn::backing-file",
257
G_FILE_QUERY_INFO_NONE,
262
g_object_unref (file);
266
if (g_cancellable_is_cancelled (priv->cancel)) {
267
g_object_unref (file);
273
g_object_unref (file);
274
g_object_unref (info);
278
if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
281
else if (g_file_info_get_file_type (info) == G_FILE_TYPE_REGULAR
282
/* NOTE: burn:// URI allows symlink */
283
|| g_file_info_get_file_type (info) == G_FILE_TYPE_SYMBOLIC_LINK) {
284
const gchar *real_path;
286
real_path = g_file_info_get_attribute_byte_string (info, "burn::backing-file");
288
priv->error = g_error_new (BRASERO_BURN_ERROR,
289
BRASERO_BURN_ERROR_GENERAL,
290
_("Impossible to retrieve local file path"));
291
g_object_unref (info);
292
g_object_unref (file);
296
*path = g_strdup (real_path);
299
g_object_unref (file);
300
g_object_unref (info);
305
brasero_burn_uri_thread (gpointer data)
307
BraseroBurnURI *self = BRASERO_BURN_URI (data);
308
BraseroTrack *current = NULL;
309
BraseroBurnURIPrivate *priv;
310
BraseroTrackData *track;
311
GSList *excluded = NULL;
312
GSList *grafts = NULL;
316
priv = BRASERO_BURN_URI_PRIVATE (self);
317
brasero_job_set_current_action (BRASERO_JOB (self),
318
BRASERO_BURN_ACTION_FILE_COPY,
319
_("Copying files locally"),
322
brasero_job_get_current_track (BRASERO_JOB (self), ¤t);
324
/* This is for IMAGE tracks */
325
if (BRASERO_IS_TRACK_IMAGE (current)) {
330
BraseroTrackImage *image;
333
uri = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (current), TRUE);
334
if (!brasero_burn_uri_retrieve_path (self, uri, &path_image)) {
341
uri = brasero_track_image_get_toc_source (BRASERO_TRACK_IMAGE (current), TRUE);
343
/* NOTE: if it's a .bin image there is not .toc file */
344
if (!brasero_burn_uri_retrieve_path (self, uri, &path_toc)) {
352
brasero_track_get_size (current, &blocks, NULL);
354
image = brasero_track_image_new ();
355
brasero_track_tag_copy_missing (BRASERO_TRACK (image), current);
356
brasero_track_image_set_source (image,
359
brasero_track_image_get_format (BRASERO_TRACK_IMAGE (current)));
360
brasero_track_image_set_block_num (image, blocks);
362
priv->track = BRASERO_TRACK (image);
369
/* This is for DATA tracks */
370
for (src = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (current)); src; src = src->next) {
373
BraseroGraftPt *graft;
378
grafts = g_slist_prepend (grafts, brasero_graft_point_copy (graft));
382
if (!g_str_has_prefix (graft->uri, "burn://")) {
383
grafts = g_slist_prepend (grafts, brasero_graft_point_copy (graft));
387
BRASERO_JOB_LOG (self, "Information retrieval for %s", graft->uri);
389
file = g_file_new_for_uri (graft->uri);
390
info = g_file_query_info (file,
391
G_FILE_ATTRIBUTE_STANDARD_NAME ","
392
G_FILE_ATTRIBUTE_STANDARD_TYPE ","
393
"burn::backing-file",
394
G_FILE_QUERY_INFO_NONE,
399
g_object_unref (file);
403
if (g_cancellable_is_cancelled (priv->cancel)) {
404
g_object_unref (file);
410
g_object_unref (file);
411
g_object_unref (info);
415
/* See if we were passed the burn:/// uri itself (the root).
416
* Then skip graft point addition */
417
if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
418
if (g_file_info_get_name (info)
419
&& strcmp (g_file_info_get_name (info), "/")) {
420
BraseroGraftPt *newgraft;
422
/* we need a dummy directory */
423
newgraft = g_new0 (BraseroGraftPt, 1);
424
newgraft->uri = NULL;
425
newgraft->path = g_strdup (graft->path);
426
grafts = g_slist_prepend (grafts, newgraft);
428
BRASERO_JOB_LOG (self,
429
"Adding directory %s at %s",
432
grafts = brasero_burn_uri_explore_directory (self,
440
BRASERO_JOB_LOG (self, "Directory is root");
441
grafts = brasero_burn_uri_explore_directory (self,
450
g_object_unref (info);
451
g_object_unref (file);
455
else if (g_file_info_get_file_type (info) == G_FILE_TYPE_REGULAR
456
/* NOTE: burn:// URI allows symlink */
457
|| g_file_info_get_file_type (info) == G_FILE_TYPE_SYMBOLIC_LINK) {
458
const gchar *real_path;
459
BraseroGraftPt *newgraft;
461
real_path = g_file_info_get_attribute_byte_string (info, "burn::backing-file");
463
priv->error = g_error_new (BRASERO_BURN_ERROR,
464
BRASERO_BURN_ERROR_GENERAL,
465
_("Impossible to retrieve local file path"));
467
g_slist_foreach (grafts, (GFunc) brasero_graft_point_free, NULL);
468
g_slist_free (grafts);
469
g_object_unref (info);
470
g_object_unref (file);
474
newgraft = brasero_graft_point_copy (graft);
475
g_free (newgraft->uri);
477
newgraft->uri = g_strdup (real_path);
478
/* FIXME: maybe one day, graft->uri will always be an URI */
479
/* newgraft->uri = g_filename_to_uri (real_path, NULL, NULL); */
481
BRASERO_JOB_LOG (self,
482
"Added file %s at %s",
485
grafts = g_slist_prepend (grafts, newgraft);
488
g_object_unref (info);
489
g_object_unref (file);
491
grafts = g_slist_reverse (grafts);
493
/* remove all excluded starting by burn:// from the list */
494
for (src = brasero_track_data_get_excluded (BRASERO_TRACK_DATA (current), FALSE); src; src = src->next) {
499
if (uri && g_str_has_prefix (uri, "burn://"))
502
uri = g_strdup (uri);
503
excluded = g_slist_prepend (excluded, uri);
505
BRASERO_JOB_LOG (self, "Added excluded file %s", uri);
507
excluded = g_slist_reverse (excluded);
509
track = brasero_track_data_new ();
510
brasero_track_tag_copy_missing (BRASERO_TRACK (track), current);
512
brasero_track_data_add_fs (track, brasero_track_data_get_fs (BRASERO_TRACK_DATA (current)));
514
brasero_track_data_get_file_num (BRASERO_TRACK_DATA (current), &num);
515
brasero_track_data_set_file_num (track, num);
517
brasero_track_data_set_source (track,
520
priv->track = BRASERO_TRACK (track);
524
if (!g_cancellable_is_cancelled (priv->cancel))
525
priv->thread_id = g_idle_add ((GSourceFunc) brasero_burn_uri_thread_finished, self);
528
g_mutex_lock (priv->mutex);
529
g_atomic_pointer_set (&priv->thread, NULL);
530
g_cond_signal (priv->cond);
531
g_mutex_unlock (priv->mutex);
533
g_thread_exit (NULL);
538
static BraseroBurnResult
539
brasero_burn_uri_start_thread (BraseroBurnURI *self,
542
BraseroBurnURIPrivate *priv;
543
GError *thread_error = NULL;
545
priv = BRASERO_BURN_URI_PRIVATE (self);
548
return BRASERO_BURN_RUNNING;
550
priv->cancel = g_cancellable_new ();
552
g_mutex_lock (priv->mutex);
553
priv->thread = g_thread_create (brasero_burn_uri_thread,
557
g_mutex_unlock (priv->mutex);
559
/* Reminder: this is not necessarily an error as the thread may have finished */
561
// return BRASERO_BURN_ERR;
563
g_propagate_error (error, thread_error);
564
return BRASERO_BURN_ERR;
567
return BRASERO_BURN_OK;
570
static BraseroBurnResult
571
brasero_burn_uri_start_if_found (BraseroBurnURI *self,
576
return BRASERO_BURN_NOT_RUNNING;
578
/* Find any graft point with burn:// URI */
579
if (!g_str_has_prefix (uri, "burn://"))
580
return BRASERO_BURN_NOT_RUNNING;
582
BRASERO_JOB_LOG (self, "burn:// URI found %s", uri);
583
brasero_burn_uri_start_thread (self, error);
584
return BRASERO_BURN_OK;
587
static BraseroBurnResult
588
brasero_burn_uri_start (BraseroJob *job,
591
BraseroBurnURIPrivate *priv;
592
BraseroBurnResult result;
593
BraseroJobAction action;
594
BraseroBurnURI *self;
599
self = BRASERO_BURN_URI (job);
600
priv = BRASERO_BURN_URI_PRIVATE (self);
603
brasero_job_get_action (job, &action);
604
if (action == BRASERO_JOB_ACTION_SIZE) {
605
/* say we won't write to disc */
606
brasero_job_set_output_size_for_current_track (job, 0, 0);
607
return BRASERO_BURN_NOT_RUNNING;
610
if (action != BRASERO_JOB_ACTION_IMAGE)
611
return BRASERO_BURN_NOT_SUPPORTED;
613
/* can't be piped so brasero_job_get_current_track will work */
614
brasero_job_get_current_track (job, &track);
616
result = BRASERO_BURN_NOT_RUNNING;
618
/* make a list of all non local uris to be downloaded and put them in a
619
* list to avoid to download the same file twice. */
620
if (BRASERO_IS_TRACK_DATA (track)) {
621
/* we put all the non local graft point uris in the hash */
622
grafts = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (track));
623
for (; grafts; grafts = grafts->next) {
624
BraseroGraftPt *graft;
626
graft = grafts->data;
627
result = brasero_burn_uri_start_if_found (self, graft->uri, error);
628
if (result != BRASERO_BURN_NOT_RUNNING)
632
else if (BRASERO_IS_TRACK_IMAGE (track)) {
633
/* NOTE: don't delete URI as they will be inserted in hash */
634
uri = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), TRUE);
635
result = brasero_burn_uri_start_if_found (self, uri, error);
638
if (result == BRASERO_BURN_NOT_RUNNING) {
639
uri = brasero_track_image_get_toc_source (BRASERO_TRACK_IMAGE (track), TRUE);
640
result = brasero_burn_uri_start_if_found (self, uri, error);
645
BRASERO_JOB_NOT_SUPPORTED (self);
648
BRASERO_JOB_LOG (self, "no burn:// URI found");
653
static BraseroBurnResult
654
brasero_burn_uri_stop (BraseroJob *job,
657
BraseroBurnURIPrivate *priv = BRASERO_BURN_URI_PRIVATE (job);
660
/* signal that we've been cancelled */
661
g_cancellable_cancel (priv->cancel);
664
g_mutex_lock (priv->mutex);
666
g_cond_wait (priv->cond, priv->mutex);
667
g_mutex_unlock (priv->mutex);
670
/* unref it after the thread has stopped */
671
g_object_unref (priv->cancel);
675
if (priv->thread_id) {
676
g_source_remove (priv->thread_id);
681
g_error_free (priv->error);
685
return BRASERO_BURN_OK;
689
brasero_burn_uri_finalize (GObject *object)
691
BraseroBurnURIPrivate *priv = BRASERO_BURN_URI_PRIVATE (object);
694
g_mutex_free (priv->mutex);
699
g_cond_free (priv->cond);
703
G_OBJECT_CLASS (parent_class)->finalize (object);
707
brasero_burn_uri_class_init (BraseroBurnURIClass *klass)
709
GObjectClass *object_class = G_OBJECT_CLASS (klass);
710
BraseroJobClass *job_class = BRASERO_JOB_CLASS (klass);
712
g_type_class_add_private (klass, sizeof (BraseroBurnURIPrivate));
714
parent_class = g_type_class_peek_parent (klass);
715
object_class->finalize = brasero_burn_uri_finalize;
717
job_class->start = brasero_burn_uri_start;
718
job_class->stop = brasero_burn_uri_stop;
722
brasero_burn_uri_init (BraseroBurnURI *obj)
724
BraseroBurnURIPrivate *priv = BRASERO_BURN_URI_PRIVATE (obj);
726
priv->mutex = g_mutex_new ();
727
priv->cond = g_cond_new ();
730
static BraseroBurnResult
731
brasero_burn_uri_export_caps (BraseroPlugin *plugin, gchar **error)
735
brasero_plugin_define (plugin,
736
/* Translators: this is the name of the plugin
737
* which will be translated only when it needs
739
N_("CD/DVD Creator Folder"),
740
_("Allows to burn files added to \"CD/DVD Creator Folder\" in Nautilus"),
744
caps = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
745
BRASERO_IMAGE_FORMAT_ANY);
746
brasero_plugin_process_caps (plugin, caps);
749
caps = brasero_caps_data_new (BRASERO_IMAGE_FS_ANY);
750
brasero_plugin_process_caps (plugin, caps);
753
brasero_plugin_set_process_flags (plugin, BRASERO_PLUGIN_RUN_PREPROCESSING);
755
return BRASERO_BURN_OK;