--- src/burn-medium.c.orig 2008-01-27 10:25:14.000000000 -0500 +++ src/burn-medium.c 2008-02-06 01:55:21.000000000 -0500 @@ -1,2070 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* - * brasero - * Copyright (C) Philippe Rouquier 2007 - * - * brasero is free software. - * - * You may redistribute it and/or modify it under the terms of the - * GNU General Public License, as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * brasero is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with brasero. If not, write to: - * The Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include -#include - -#include -#include - -#include - -#include "burn-basics.h" -#include "burn-debug.h" -#include "burn-medium.h" -#include "scsi-mmc1.h" -#include "scsi-mmc2.h" -#include "scsi-mmc3.h" -#include "scsi-spc1.h" -#include "scsi-utils.h" -#include "scsi-mode-pages.h" -#include "scsi-status-page.h" -#include "scsi-q-subchannel.h" -#include "scsi-dvd-structures.h" -#include "burn-volume.h" -#include "brasero-ncb.h" - -const gchar *icons [] = { "gnome-dev-removable", - "gnome-dev-cdrom", - "gnome-dev-disc-cdr", - "gnome-dev-disc-cdrw", - "gnome-dev-disc-dvdrom", - "gnome-dev-disc-dvdr", - "gnome-dev-disc-dvdrw", - "gnome-dev-disc-dvdr-plus", - "gnome-dev-disc-dvdram", - NULL }; -const gchar *types [] = { N_("file"), - N_("CDROM"), - N_("CD-R"), - N_("CD-RW"), - N_("DVDROM"), - N_("DVD-R"), - N_("DVD-RW"), - N_("DVD+R"), - N_("DVD+RW"), - N_("DVD+R dual layer"), - N_("DVD+RW dual layer"), - N_("DVD-R dual layer"), - N_("DVD-RAM"), - N_("Blu-ray disc"), - N_("Writable Blu-ray disc"), - N_("Rewritable Blu-ray disc"), - NULL }; - - -typedef struct _BraseroMediumPrivate BraseroMediumPrivate; -struct _BraseroMediumPrivate -{ - gint retry_id; - - GSList * tracks; - - const gchar *type; - const gchar *icon; - - gint max_rd; - gint max_wrt; - - gint *rd_speeds; - gint *wr_speeds; - - gint64 block_num; - gint64 block_size; - - guint64 next_wr_add; - BraseroMedia info; - NautilusBurnDrive * drive; -}; - -#define BRASERO_MEDIUM_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_MEDIUM, BraseroMediumPrivate)) - -/** - * Try to open the drive exclusively but don't block; if drive can't be opened - * exclusively then retry every second until we're shut or the drive state - * changes to not busy. - * No exclusive at the moment since when the medium is mounted we can't use excl - */ - -#define OPEN_FLAGS O_RDONLY /*|O_EXCL */|O_NONBLOCK -#define BUSY_RETRY_TIME 1000 - -enum -{ - PROP_0, - PROP_DRIVE -}; - -static GObjectClass* parent_class = NULL; - -const gchar * -brasero_medium_get_type_string (BraseroMedium *medium) -{ - BraseroMediumPrivate *priv; - - priv = BRASERO_MEDIUM_PRIVATE (medium); - return priv->type; -} - -const gchar * -brasero_medium_get_icon (BraseroMedium *medium) -{ - BraseroMediumPrivate *priv; - - priv = BRASERO_MEDIUM_PRIVATE (medium); - return priv->icon; -} - -BraseroMedia -brasero_medium_get_status (BraseroMedium *medium) -{ - BraseroMediumPrivate *priv; - - priv = BRASERO_MEDIUM_PRIVATE (medium); - return priv->info; -} - -GSList * -brasero_medium_get_tracks (BraseroMedium *medium) -{ - BraseroMediumPrivate *priv; - - priv = BRASERO_MEDIUM_PRIVATE (medium); - return g_slist_copy (priv->tracks); -} - -gboolean -brasero_medium_get_last_data_track_address (BraseroMedium *medium, - gint64 *byte, - gint64 *sector) -{ - GSList *iter; - BraseroMediumPrivate *priv; - BraseroMediumTrack *track = NULL; - - priv = BRASERO_MEDIUM_PRIVATE (medium); - - for (iter = priv->tracks; iter; iter = iter->next) { - BraseroMediumTrack *current; - - current = iter->data; - if (current->type & BRASERO_MEDIUM_TRACK_DATA) - track = current; - } - - if (!track) { - if (byte) - *byte = -1; - if (sector) - *sector = -1; - return FALSE; - } - - if (byte) - *byte = track->start * priv->block_size; - - if (sector) - *sector = track->start; - - return TRUE; -} - -gboolean -brasero_medium_get_last_data_track_space (BraseroMedium *medium, - gint64 *size, - gint64 *blocks) -{ - GSList *iter; - BraseroMediumPrivate *priv; - BraseroMediumTrack *track = NULL; - - priv = BRASERO_MEDIUM_PRIVATE (medium); - - for (iter = priv->tracks; iter; iter = iter->next) { - BraseroMediumTrack *current; - - current = iter->data; - if (current->type & BRASERO_MEDIUM_TRACK_DATA) - track = current; - } - - if (!track) { - if (size) - *size = -1; - if (blocks) - *blocks = -1; - return FALSE; - } - - if (size) - *size = track->blocks_num * priv->block_size; - if (blocks) - *blocks = track->blocks_num; - - return TRUE; -} - -guint -brasero_medium_get_track_num (BraseroMedium *medium) -{ - guint retval = 0; - GSList *iter; - BraseroMediumPrivate *priv; - - priv = BRASERO_MEDIUM_PRIVATE (medium); - for (iter = priv->tracks; iter; iter = iter->next) { - BraseroMediumTrack *current; - - current = iter->data; - if (current->type & BRASERO_MEDIUM_TRACK_LEADOUT) - break; - - retval ++; - } - - return retval; -} - -static BraseroMediumTrack * -brasero_medium_get_track (BraseroMedium *medium, - guint num) -{ - guint i = 1; - GSList *iter; - BraseroMediumPrivate *priv; - - priv = BRASERO_MEDIUM_PRIVATE (medium); - - for (iter = priv->tracks; iter; iter = iter->next) { - BraseroMediumTrack *current; - - current = iter->data; - if (current->type == BRASERO_MEDIUM_TRACK_LEADOUT) - break; - - if (i == num) - return current; - - i++; - } - - return NULL; -} - -gboolean -brasero_medium_get_track_space (BraseroMedium *medium, - guint num, - gint64 *size, - gint64 *blocks) -{ - BraseroMediumPrivate *priv; - BraseroMediumTrack *track; - - priv = BRASERO_MEDIUM_PRIVATE (medium); - - track = brasero_medium_get_track (medium, num); - if (!track) { - if (size) - *size = -1; - if (blocks) - *blocks = -1; - return FALSE; - } - - if (size) - *size = track->blocks_num * priv->block_size; - if (blocks) - *blocks = track->blocks_num; - - return TRUE; -} - -gboolean -brasero_medium_get_track_address (BraseroMedium *medium, - guint num, - gint64 *byte, - gint64 *sector) -{ - BraseroMediumPrivate *priv; - BraseroMediumTrack *track; - - priv = BRASERO_MEDIUM_PRIVATE (medium); - - track = brasero_medium_get_track (medium, num); - if (!track) { - if (byte) - *byte = -1; - if (sector) - *sector = -1; - return FALSE; - } - - if (byte) - *byte = track->start * priv->block_size; - if (sector) - *sector = track->start; - - return TRUE; -} - -gint64 -brasero_medium_get_next_writable_address (BraseroMedium *medium) -{ - BraseroMediumPrivate *priv; - - priv = BRASERO_MEDIUM_PRIVATE (medium); - return priv->next_wr_add; -} - -gint64 -brasero_medium_get_max_write_speed (BraseroMedium *medium) -{ - BraseroMediumPrivate *priv; - - priv = BRASERO_MEDIUM_PRIVATE (medium); - return priv->max_wrt * 1024; -} - -/** - * NOTEs about the following functions: - * for all closed media (including ROM types) capacity == size of data and - * should be the size of all data on the disc, free space is 0 - * for all blank -R types capacity == free space and size of data == 0 - * for all multisession -R types capacity == free space since having the real - * capacity of the media would be useless as we can only use this type of media - * to append more data - * for all -RW types capacity = free space + size of data. Here they can be - * appended (use free space) or rewritten (whole capacity). - * - * Usually: - * the free space is the size of the leadout track - * the size of data is the sum of track sizes (excluding leadout) - * the capacity depends on the media: - * for closed discs == sum of track sizes - * for multisession discs == free space (leadout size) - * for blank discs == (free space) leadout size - * for rewritable/blank == use SCSI functions to get capacity (see below) - * - * In fact we should really need the size of data in DVD+/-RW cases since the - * session is always equal to the size of the disc. - */ - -void -brasero_medium_get_data_size (BraseroMedium *medium, - gint64 *size, - gint64 *blocks) -{ - GSList *iter; - BraseroMediumPrivate *priv; - BraseroMediumTrack *track = NULL; - - priv = BRASERO_MEDIUM_PRIVATE (medium); - - if (!priv->tracks) { - /* that's probably because it wasn't possible to retrieve info */ - if (size) - *size = 0; - - if (blocks) - *blocks = 0; - - return; - } - - for (iter = priv->tracks; iter; iter = iter->next) { - BraseroMediumTrack *tmp; - - tmp = iter->data; - if (tmp->type == BRASERO_MEDIUM_TRACK_LEADOUT) - break; - - track = iter->data; - } - - if (size) - *size = track ? (track->start + track->blocks_num) * priv->block_size: 0; - - if (blocks) - *blocks = track ? track->start + track->blocks_num: 0; -} - -void -brasero_medium_get_free_space (BraseroMedium *medium, - gint64 *size, - gint64 *blocks) -{ - GSList *iter; - BraseroMediumPrivate *priv; - BraseroMediumTrack *track = NULL; - - priv = BRASERO_MEDIUM_PRIVATE (medium); - - if (!priv->tracks) { - /* that's probably because it wasn't possible to retrieve info. - * maybe it also happens with unformatted DVD+RW */ - - if (priv->info & BRASERO_MEDIUM_CLOSED) { - if (size) - *size = 0; - - if (blocks) - *blocks = 0; - } - else { - if (size) - *size = priv->block_num * priv->block_size; - - if (blocks) - *blocks = priv->block_num; - } - - return; - } - - for (iter = priv->tracks; iter; iter = iter->next) { - BraseroMediumTrack *tmp; - - tmp = iter->data; - if (tmp->type == BRASERO_MEDIUM_TRACK_LEADOUT) { - track = iter->data; - break; - } - } - - if (size) { - if (!track) { - /* No leadout was found so the disc is probably closed: - * no free space left. */ - *size = 0; - } - else if (track->blocks_num <= 0) - *size = (priv->block_num - track->start) * priv->block_size; - else - *size = track->blocks_num * priv->block_size; - } - - if (blocks) { - if (!track) { - /* No leadout was found so the disc is probably closed: - * no free space left. */ - *blocks = 0; - } - else if (track->blocks_num <= 0) - *blocks = priv->block_num - track->blocks_num; - else - *blocks = track->blocks_num; - } -} - -void -brasero_medium_get_capacity (BraseroMedium *medium, - gint64 *size, - gint64 *blocks) -{ - BraseroMediumPrivate *priv; - - priv = BRASERO_MEDIUM_PRIVATE (medium); - - if (priv->info & BRASERO_MEDIUM_REWRITABLE) { - if (size) - *size = priv->block_num * priv->block_size; - - if (blocks) - *blocks = priv->block_num; - } - else if (priv->info & BRASERO_MEDIUM_CLOSED) - brasero_medium_get_data_size (medium, size, blocks); - else - brasero_medium_get_free_space (medium, size, blocks); -} - -/** - * Function to retrieve the capacity of a media - */ - -static BraseroBurnResult -brasero_medium_get_capacity_CD_RW (BraseroMedium *self, - int fd, - BraseroScsiErrCode *code) -{ - BraseroScsiAtipData *atip_data = NULL; - BraseroMediumPrivate *priv; - BraseroScsiResult result; - int size = 0; - - priv = BRASERO_MEDIUM_PRIVATE (self); - - BRASERO_BURN_LOG ("Retrieving capacity from atip"); - - result = brasero_mmc1_read_atip (fd, - &atip_data, - &size, - NULL); - - if (result != BRASERO_SCSI_OK) { - BRASERO_BURN_LOG ("READ ATIP failed (scsi error)"); - return BRASERO_BURN_ERR; - } - - /* check the size of the structure: it must be at least 16 bytes long */ - if (size < 16) { - if (size) - g_free (atip_data); - - BRASERO_BURN_LOG ("READ ATIP failed (wrong size)"); - return BRASERO_BURN_ERR; - } - - priv->block_num = BRASERO_MSF_TO_LBA (atip_data->desc->leadout_mn, - atip_data->desc->leadout_sec, - atip_data->desc->leadout_frame); - g_free (atip_data); - - BRASERO_BURN_LOG ("Format capacity %lli %lli", - priv->block_num, - priv->block_size); - - return BRASERO_BURN_OK; -} - -static BraseroBurnResult -brasero_medium_get_capacity_DVD_RW (BraseroMedium *self, - int fd, - BraseroScsiErrCode *code) -{ - BraseroScsiFormatCapacitiesHdr *hdr = NULL; - BraseroScsiMaxCapacityDesc *current; - BraseroMediumPrivate *priv; - BraseroScsiResult result; - gint size; - - BRASERO_BURN_LOG ("Retrieving format capacity"); - - priv = BRASERO_MEDIUM_PRIVATE (self); - result = brasero_mmc2_read_format_capacities (fd, - &hdr, - &size, - code); - if (result != BRASERO_SCSI_OK) { - g_free (hdr); - - BRASERO_BURN_LOG ("READ FORMAT CAPACITIES failed"); - return BRASERO_BURN_ERR; - } - - current = hdr->max_caps; - - /* see if the media is already formatted */ - if (current->type != BRASERO_SCSI_DESC_FORMATTED) { - int i, max; - BraseroScsiFormattableCapacityDesc *desc; - - max = (hdr->len - - sizeof (BraseroScsiMaxCapacityDesc)) / - sizeof (BraseroScsiFormattableCapacityDesc); - - desc = hdr->desc; - for (i = 0; i < max; i ++, desc ++) { - /* search for the correct descriptor */ - if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DVDRW_PLUS)) { - if (desc->format_type == BRASERO_SCSI_DVDRW_PLUS) { - priv->block_num = BRASERO_GET_32 (desc->blocks_num); - priv->block_size = BRASERO_GET_24 (desc->type_param); - - /* that can happen */ - if (!priv->block_size) - priv->block_size = 2048; - break; - } - } - else if (desc->format_type == BRASERO_SCSI_BLOCK_SIZE_DEFAULT_AND_DB) { - priv->block_num = BRASERO_GET_32 (desc->blocks_num); - priv->block_size = BRASERO_GET_24 (desc->type_param); - break; - } - } - } - else { - priv->block_num = BRASERO_GET_32 (current->blocks_num); - priv->block_size = BRASERO_GET_24 (current->block_size); - } - - BRASERO_BURN_LOG ("Format capacity %lli %lli", - priv->block_num, - priv->block_size); - - g_free (hdr); - return BRASERO_BURN_OK; -} - -static BraseroBurnResult -brasero_medium_get_capacity_by_type (BraseroMedium *self, - int fd, - BraseroScsiErrCode *code) -{ - BraseroMediumPrivate *priv; - - priv = BRASERO_MEDIUM_PRIVATE (self); - - priv->block_size = 2048; - - if (!(priv->info & BRASERO_MEDIUM_REWRITABLE)) - return BRASERO_BURN_OK; - - if (priv->info & BRASERO_MEDIUM_CD) - brasero_medium_get_capacity_CD_RW (self, fd, code); - else - brasero_medium_get_capacity_DVD_RW (self, fd, code); - - return BRASERO_BURN_OK; -} - -/** - * Functions to retrieve the speed - */ - -static BraseroBurnResult -brasero_medium_get_speed_mmc3 (BraseroMedium *self, - int fd, - BraseroScsiErrCode *code) -{ - int size; - int num_desc, i; - gint max_rd, max_wrt; - BraseroScsiResult result; - BraseroMediumPrivate *priv; - BraseroScsiWrtSpdDesc *desc; - BraseroScsiGetPerfData *wrt_perf = NULL; - - BRASERO_BURN_LOG ("Retrieving speed (Get Performance)"); - - /* NOTE: this only work if there is RT streaming feature with - * wspd bit set to 1. At least an MMC3 drive. */ - priv = BRASERO_MEDIUM_PRIVATE (self); - result = brasero_mmc3_get_performance_wrt_spd_desc (fd, - &wrt_perf, - &size, - code); - - if (result != BRASERO_SCSI_OK) { - g_free (wrt_perf); - - BRASERO_BURN_LOG ("GET PERFORMANCE failed"); - return BRASERO_BURN_ERR; - } - - num_desc = (size - sizeof (BraseroScsiGetPerfHdr)) / - sizeof (BraseroScsiWrtSpdDesc); - - if (num_desc <= 0) - goto end; - - priv->rd_speeds = g_new0 (gint, num_desc + 1); - priv->wr_speeds = g_new0 (gint, num_desc + 1); - - max_rd = 0; - max_wrt = 0; - - desc = (BraseroScsiWrtSpdDesc*) &wrt_perf->data; - for (i = 0; i < num_desc; i ++, desc ++) { - priv->rd_speeds [i] = BRASERO_GET_32 (desc->rd_speed); - priv->wr_speeds [i] = BRASERO_GET_32 (desc->wr_speed); - - max_rd = MAX (max_rd, priv->rd_speeds [i]); - max_wrt = MAX (max_wrt, priv->wr_speeds [i]); - } - - priv->max_rd = max_rd; - priv->max_wrt = max_wrt; - -end: - - g_free (wrt_perf); - - /* strangely there are so drives (I know one case) which support this - * function but don't report any speed. So if our top speed is 0 then - * use the other way to get the speed. It was a Teac */ - if (!priv->max_wrt) - return BRASERO_BURN_ERR; - - return BRASERO_BURN_OK; -} - -static BraseroBurnResult -brasero_medium_get_page_2A_write_speed_desc (BraseroMedium *self, - int fd, - BraseroScsiErrCode *code) -{ - BraseroScsiStatusPage *page_2A = NULL; - BraseroScsiStatusWrSpdDesc *desc; - BraseroScsiModeData *data = NULL; - BraseroMediumPrivate *priv; - BraseroScsiResult result; - gint desc_num, i; - gint max_wrt = 0; - gint max_num; - int size = 0; - - BRASERO_BURN_LOG ("Retrieving speed (2A speeds)"); - - priv = BRASERO_MEDIUM_PRIVATE (self); - result = brasero_spc1_mode_sense_get_page (fd, - BRASERO_SPC_PAGE_STATUS, - &data, - &size, - code); - if (result != BRASERO_SCSI_OK) { - g_free (data); - - BRASERO_BURN_LOG ("MODE SENSE failed"); - return BRASERO_BURN_ERR; - } - - page_2A = (BraseroScsiStatusPage *) &data->page; - - /* FIXME: the following is not necessarily true */ - if (size < sizeof (BraseroScsiStatusPage)) { - g_free (data); - - BRASERO_BURN_LOG ("wrong size in page"); - return BRASERO_BURN_ERR; - } - - desc_num = BRASERO_GET_16 (page_2A->wr_speed_desc_num); - max_num = size - - sizeof (BraseroScsiStatusPage) - - sizeof (BraseroScsiModeHdr); - max_num /= sizeof (BraseroScsiWrtSpdDesc); - - if (max_num < 0) - max_num = 0; - - if (desc_num > max_num) - desc_num = max_num; - - priv->wr_speeds = g_new0 (gint, desc_num + 1); - desc = page_2A->wr_spd_desc; - for (i = 0; i < desc_num; i ++, desc ++) { - priv->wr_speeds [i] = BRASERO_GET_16 (desc->speed); - max_wrt = MAX (max_wrt, priv->wr_speeds [i]); - } - - if (!max_wrt) - priv->max_wrt = BRASERO_GET_16 (page_2A->wr_max_speed); - else - priv->max_wrt = max_wrt; - - priv->max_rd = BRASERO_GET_16 (page_2A->rd_max_speed); - g_free (data); - - return BRASERO_BURN_OK; -} - -static BraseroBurnResult -brasero_medium_get_page_2A_max_speed (BraseroMedium *self, - int fd, - BraseroScsiErrCode *code) -{ - BraseroScsiStatusPage *page_2A = NULL; - BraseroScsiModeData *data = NULL; - BraseroMediumPrivate *priv; - BraseroScsiResult result; - int size = 0; - - BRASERO_BURN_LOG ("Retrieving speed (2A max)"); - - priv = BRASERO_MEDIUM_PRIVATE (self); - - result = brasero_spc1_mode_sense_get_page (fd, - BRASERO_SPC_PAGE_STATUS, - &data, - &size, - code); - if (result != BRASERO_SCSI_OK) { - g_free (data); - - BRASERO_BURN_LOG ("MODE SENSE failed"); - return BRASERO_BURN_ERR; - } - - page_2A = (BraseroScsiStatusPage *) &data->page; - - if (size < 0x14) { - g_free (data); - - BRASERO_BURN_LOG ("wrong page size"); - return BRASERO_BURN_ERR; - } - - priv->max_rd = BRASERO_GET_16 (page_2A->rd_max_speed); - priv->max_wrt = BRASERO_GET_16 (page_2A->wr_max_speed); - - g_free (data); - return BRASERO_BURN_OK; -} - -static BraseroBurnResult -brasero_medium_get_medium_type (BraseroMedium *self, - int fd, - BraseroScsiErrCode *code) -{ - BraseroScsiGetConfigHdr *hdr = NULL; - BraseroMediumPrivate *priv; - BraseroScsiResult result; - int size; - - BRASERO_BURN_LOG ("Retrieving media profile"); - - priv = BRASERO_MEDIUM_PRIVATE (self); - result = brasero_mmc2_get_configuration_feature (fd, - BRASERO_SCSI_FEAT_REAL_TIME_STREAM, - &hdr, - &size, - code); - if (result != BRASERO_SCSI_OK) { - BraseroScsiAtipData *data = NULL; - int size = 0; - - BRASERO_BURN_LOG ("GET CONFIGURATION failed"); - - /* This could be a MMC1 drive since this command was - * introduced in MMC2 and is supported onward. So it - * has to be a CD (R/RW). The rest of the information - * will be provided by read_disc_information. */ - - /* The only thing here left to determine is if that's a WRITABLE - * or a REWRITABLE. To determine that information, we need to - * read TocPmaAtip. It if fails that's a ROM, if it succeeds. - * No need to set error code since we consider that it's a ROM - * if a failure happens. */ - result = brasero_mmc1_read_atip (fd, - &data, - &size, - NULL); - if (result != BRASERO_SCSI_OK) { - /* CDROM */ - priv->info = BRASERO_MEDIUM_CDROM; - priv->type = types [1]; - priv->icon = icons [1]; - } - else { - /* check the size of the structure: it must be at least 8 bytes long */ - if (size < 8) { - if (size) - g_free (data); - - BRASERO_BURN_LOG ("READ ATIP failed (wrong size)"); - return BRASERO_BURN_ERR; - } - - if (data->desc->erasable) { - /* CDRW */ - priv->info = BRASERO_MEDIUM_CDRW; - priv->type = types [3]; - priv->icon = icons [3]; - } - else { - /* CDR */ - priv->info = BRASERO_MEDIUM_CDR; - priv->type = types [2]; - priv->icon = icons [2]; - } - - g_free (data); - } - - /* retrieve the speed */ - result = brasero_medium_get_page_2A_max_speed (self, - fd, - code); - return result; - } - - switch (BRASERO_GET_16 (hdr->current_profile)) { - case BRASERO_SCSI_PROF_CDROM: - priv->info = BRASERO_MEDIUM_CDROM; - priv->type = types [1]; - priv->icon = icons [1]; - break; - - case BRASERO_SCSI_PROF_CDR: - priv->info = BRASERO_MEDIUM_CDR; - priv->type = types [2]; - priv->icon = icons [2]; - break; - - case BRASERO_SCSI_PROF_CDRW: - priv->info = BRASERO_MEDIUM_CDRW; - priv->type = types [3]; - priv->icon = icons [3]; - break; - - case BRASERO_SCSI_PROF_DVD_ROM: - priv->info = BRASERO_MEDIUM_DVD_ROM; - priv->type = types [4]; - priv->icon = icons [4]; - break; - - case BRASERO_SCSI_PROF_DVD_R: - priv->info = BRASERO_MEDIUM_DVDR; - priv->type = types [5]; - priv->icon = icons [5]; - break; - - case BRASERO_SCSI_PROF_DVD_RW_RESTRICTED: - priv->info = BRASERO_MEDIUM_DVDRW_RESTRICTED; - priv->type = types [6]; - priv->icon = icons [6]; - break; - - case BRASERO_SCSI_PROF_DVD_RW_SEQUENTIAL: - priv->info = BRASERO_MEDIUM_DVDRW; - priv->type = types [6]; - priv->icon = icons [6]; - break; - - case BRASERO_SCSI_PROF_DVD_R_PLUS: - priv->info = BRASERO_MEDIUM_DVDR_PLUS; - priv->type = types [7]; - priv->icon = icons [7]; - break; - - case BRASERO_SCSI_PROF_DVD_RW_PLUS: - priv->info = BRASERO_MEDIUM_DVDRW_PLUS; - priv->type = types [8]; - priv->icon = icons [7]; - break; - - /* WARNING: these types are recognized, no more */ - case BRASERO_SCSI_PROF_DVD_R_PLUS_DL: - priv->info = BRASERO_MEDIUM_DVDR_PLUS_DL; - priv->type = types [9]; - priv->icon = icons [7]; - break; - - case BRASERO_SCSI_PROF_DVD_RW_PLUS_DL: - priv->info = BRASERO_MEDIUM_DVDRW_PLUS_DL; - priv->type = types [10]; - priv->icon = icons [7]; - break; - - case BRASERO_SCSI_PROF_DVD_R_DL_SEQUENTIAL: - priv->info = BRASERO_MEDIUM_DVDR_DL; - priv->type = types [11]; - priv->icon = icons [5]; - break; - - case BRASERO_SCSI_PROF_DVD_R_DL_JUMP: - priv->info = BRASERO_MEDIUM_DVDR_JUMP_DL; - priv->type = types [11]; - priv->icon = icons [5]; - break; - - case BRASERO_SCSI_PROF_DVD_RAM: - priv->info = BRASERO_MEDIUM_DVD_RAM; - priv->type = types [12]; - priv->icon = icons [8]; - break; - - case BRASERO_SCSI_PROF_BD_ROM: - priv->info = BRASERO_MEDIUM_BD_ROM; - priv->type = types [13]; - priv->icon = icons [4]; - break; - - case BRASERO_SCSI_PROF_BR_R_SEQUENTIAL: - priv->info = BRASERO_MEDIUM_BDR; - priv->type = types [14]; - priv->icon = icons [5]; - break; - - case BRASERO_SCSI_PROF_BR_R_RANDOM: - priv->info = BRASERO_MEDIUM_BDR_RANDOM; - priv->type = types [14]; - priv->icon = icons [5]; - break; - - case BRASERO_SCSI_PROF_BD_RW: - priv->info = BRASERO_MEDIUM_BDRW; - priv->type = types [15]; - priv->icon = icons [6]; - break; - - case BRASERO_SCSI_PROF_NON_REMOVABLE: - case BRASERO_SCSI_PROF_REMOVABLE: - case BRASERO_SCSI_PROF_MO_ERASABLE: - case BRASERO_SCSI_PROF_MO_WRITE_ONCE: - case BRASERO_SCSI_PROF_MO_ADVANCED_STORAGE: - case BRASERO_SCSI_PROF_DDCD_ROM: - case BRASERO_SCSI_PROF_DDCD_R: - case BRASERO_SCSI_PROF_DDCD_RW: - case BRASERO_SCSI_PROF_HD_DVD_ROM: - case BRASERO_SCSI_PROF_HD_DVD_R: - case BRASERO_SCSI_PROF_HD_DVD_RAM: - priv->info = BRASERO_MEDIUM_UNSUPPORTED; - priv->icon = icons [0]; - g_free (hdr); - return BRASERO_BURN_NOT_SUPPORTED; - } - - /* try all SCSI functions to get write/read speeds in order */ - if (hdr->desc->add_len >= sizeof (BraseroScsiRTStreamDesc)) { - BraseroScsiRTStreamDesc *stream; - - /* means it's at least an MMC3 drive */ - stream = (BraseroScsiRTStreamDesc *) hdr->desc->data; - if (stream->wrt_spd) { - result = brasero_medium_get_speed_mmc3 (self, fd, code); - if (result == BRASERO_BURN_OK) - goto end; - } - - if (stream->mp2a) { - result = brasero_medium_get_page_2A_write_speed_desc (self, fd, code); - if (result == BRASERO_BURN_OK) - goto end; - } - } - - /* fallback for speeds */ - result = brasero_medium_get_page_2A_max_speed (self, fd, code); - -end: - - g_free (hdr); - - if (result != BRASERO_BURN_OK) - return result; - - return BRASERO_BURN_OK; -} - -static BraseroBurnResult -brasero_medium_get_css_feature (BraseroMedium *self, - int fd, - BraseroScsiErrCode *code) -{ - BraseroScsiGetConfigHdr *hdr = NULL; - BraseroMediumPrivate *priv; - BraseroScsiResult result; - int size; - - priv = BRASERO_MEDIUM_PRIVATE (self); - - BRASERO_BURN_LOG ("Testing for Css encrypted media"); - result = brasero_mmc2_get_configuration_feature (fd, - BRASERO_SCSI_FEAT_DVD_CSS, - &hdr, - &size, - code); - if (result != BRASERO_SCSI_OK) { - g_free (hdr); - - BRASERO_BURN_LOG ("GET CONFIGURATION failed"); - return BRASERO_BURN_ERR; - } - - if (hdr->desc->add_len < sizeof (BraseroScsiDVDCssDesc)) { - g_free (hdr); - return BRASERO_BURN_OK; - } - - /* here we just need to see if this feature is current or not */ - if (hdr->desc->current) { - priv->info |= BRASERO_MEDIUM_PROTECTED; - BRASERO_BURN_LOG ("media is Css protected"); - } - - g_free (hdr); - return BRASERO_BURN_OK; -} - -/** - * Functions to get information about disc contents - */ - -static void -brasero_medium_set_track_type (BraseroMedium *self, - BraseroMediumTrack *track, - guchar control) -{ - BraseroMediumPrivate *priv; - - priv = BRASERO_MEDIUM_PRIVATE (self); - - if (control & BRASERO_SCSI_TRACK_COPY) - track->type |= BRASERO_MEDIUM_TRACK_COPY; - - if (!(control & BRASERO_SCSI_TRACK_DATA)) { - track->type |= BRASERO_MEDIUM_TRACK_AUDIO; - priv->info |= BRASERO_MEDIUM_HAS_AUDIO; - - if (control & BRASERO_SCSI_TRACK_PREEMP) - track->type |= BRASERO_MEDIUM_TRACK_PREEMP; - - if (control & BRASERO_SCSI_TRACK_4_CHANNELS) - track->type |= BRASERO_MEDIUM_TRACK_4_CHANNELS; - } - else { - track->type |= BRASERO_MEDIUM_TRACK_DATA; - priv->info |= BRASERO_MEDIUM_HAS_DATA; - - if (control & BRASERO_SCSI_TRACK_DATA_INCREMENTAL) - track->type |= BRASERO_MEDIUM_TRACK_INCREMENTAL; - } -} - -static BraseroBurnResult -brasero_medium_track_volume_size (BraseroMedium *self, - BraseroMediumTrack *track, - int fd) -{ - BraseroMediumPrivate *priv; - BraseroBurnResult res; - GError *error = NULL; - gint64 nb_blocks; - - if (!track) - return BRASERO_BURN_ERR; - - priv = BRASERO_MEDIUM_PRIVATE (self); - - /* This is a special case. For DVD+RW and DVD-RW in restricted - * mode, there is only one session that takes the whole disc size - * once formatted. That doesn't necessarily means they have data - * Note also that they are reported as complete though you can - * still add data (with growisofs). It is nevertheless on the - * condition that the fs is valid. - * So we check if their first and only volume is valid. - * That's also used when the track size is reported a 300 Kio - * see below */ - res = brasero_volume_get_size_fd (fd, - track->start, - &nb_blocks, - NULL); - if (!res) { - BRASERO_BURN_LOG ("Failed to retrieve the volume size: %s", - error && error->message ? - error->message:"unknown error"); - - if (error) - g_error_free (error); - return BRASERO_BURN_ERR; - } - - track->blocks_num = nb_blocks; - return BRASERO_BURN_OK; -} - -static BraseroBurnResult -brasero_medium_track_get_info (BraseroMedium *self, - BraseroMediumTrack *track, - int track_num, - int fd, - BraseroScsiErrCode *code) -{ - BraseroScsiTrackInfo track_info; - BraseroMediumPrivate *priv; - BraseroScsiResult result; - int size; - - BRASERO_BURN_LOG ("Retrieving track information for %i", track_num); - - priv = BRASERO_MEDIUM_PRIVATE (self); - - /* at this point we know the type of the disc that's why we set the - * size according to this type. That may help to avoid outrange address - * errors. */ - if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DL|BRASERO_MEDIUM_WRITABLE)) - size = 48; - else if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_PLUS|BRASERO_MEDIUM_WRITABLE)) - size = 40; - else - size = 36; - - result = brasero_mmc1_read_track_info (fd, - track_num, - &track_info, - &size, - code); - - if (result != BRASERO_SCSI_OK) { - BRASERO_BURN_LOG ("READ TRACK INFO failed"); - return BRASERO_BURN_ERR; - } - - track->blocks_num = BRASERO_GET_32 (track_info.track_size); - track->session = BRASERO_SCSI_SESSION_NUM (track_info); - - /* Now here is a potential bug: we can write tracks (data or not) - * shorter than 300 Kio /2 sec but they will be padded to reach this - * floor value. That means that is blocks_num is 300 blocks that may - * mean that the data length on the track is actually shorter. - * So we read the volume descriptor. If it works, good otherwise - * use the old value. - * That's important for checksuming to have a perfect account of the - * data size. */ - if (track->blocks_num <= 300) { - BRASERO_BURN_LOG ("300 sectors size. Checking for real size"); - brasero_medium_track_volume_size (self, track, fd); - } - - if (track_info.next_wrt_address_valid) - priv->next_wr_add = BRASERO_GET_32 (track_info.next_wrt_address); - - BRASERO_BURN_LOG ("Track %i (session %i): type = %i start = %llu size = %llu", - track_num, - track->session, - track->type, - track->start, - track->blocks_num); - - return BRASERO_BURN_OK; -} - -/** - * return : - * 0 when it's not possible to determine (fallback to formatted toc) - * -1 for BCD - * 1 for HEX */ -static guint -brasero_medium_check_BCD_use (BraseroMedium *self, - int fd, - BraseroScsiRawTocDesc *desc, - guint num, - BraseroScsiErrCode *code) -{ - guint i; - int size; - guint leadout = 0; - guint track_num = 0; - gboolean use_BCD = TRUE; - gboolean use_HEX = TRUE; - BraseroScsiResult result; - BraseroScsiTrackInfo track_info; - guint start_BCD, start_LBA, track_start; - - /* first check if all values are valid BCD numbers in the descriptors */ - for (i = 0; i < num; i++) { - if (desc [i].adr == 1 && desc [i].point <= BRASERO_SCSI_Q_SUB_CHANNEL_TRACK_START) { - if (!BRASERO_IS_BCD_VALID (desc [i].p_min) - || !BRASERO_IS_BCD_VALID (desc [i].p_sec) - || !BRASERO_IS_BCD_VALID (desc [i].p_frame)) { - use_BCD = FALSE; - break; - } - } - else if (desc [i].point == BRASERO_SCSI_Q_SUB_CHANNEL_LEADOUT_START) { - if (!BRASERO_IS_BCD_VALID (desc [i].p_min) - || !BRASERO_IS_BCD_VALID (desc [i].p_sec) - || !BRASERO_IS_BCD_VALID (desc [i].p_frame)) { - use_BCD = FALSE; - break; - } - } - } - - /* then check if there are valid Hex values */ - for (i = 0; i < num; i++) { - if (desc [i].adr != 1 || desc [i].point > BRASERO_SCSI_Q_SUB_CHANNEL_TRACK_START) - continue; - - if (desc [i].p_min > 99 - || desc [i].p_sec > 59 - || desc [i].p_frame > 74) { - use_HEX = FALSE; - break; - } - } - - if (use_BCD != use_HEX) { - if (use_BCD) - return -1; - - return 1; - } - - /* To check if the drive uses BCD values or HEX values we ask for the - * track information that contains also the start for the track but in - * HEX values. If values are the same then it works. */ - - /* NOTE: there could be another way to do it: get first track, in LBA - * and BCD it must be 150. */ - - /* First find the first track and get track start address in BCD */ - BRASERO_BURN_LOG ("Retrieving track information to determine number format"); - - for (i = 0; i < num; i++) { - if (desc [i].adr == BRASERO_SCSI_Q_SUB_CHANNEL_LEADIN_MODE5 - && desc [i].point == BRASERO_SCSI_Q_SUB_CHANNEL_MULTI_NEXT_SESSION) { - /* store the leadout number just in case */ - leadout = i; - continue; - } - - if (desc [i].adr != 1 || desc [i].point > BRASERO_SCSI_Q_SUB_CHANNEL_TRACK_START) - continue; - - track_num ++; - - start_BCD = BRASERO_MSF_TO_LBA (BRASERO_GET_BCD (desc [i].p_min), - BRASERO_GET_BCD (desc [i].p_sec), - BRASERO_GET_BCD (desc [i].p_frame)); - - start_LBA = BRASERO_MSF_TO_LBA (desc [i].p_min, - desc [i].p_sec, - desc [i].p_frame); - - BRASERO_BURN_LOG ("Comparing to track information from READ TRACK INFO for track %i", track_num); - - size = 36; - start_LBA -= 150; - start_BCD -= 150; - - result = brasero_mmc1_read_track_info (fd, - track_num, - &track_info, - &size, - code); - - if (result != BRASERO_SCSI_OK) { - BRASERO_BURN_LOG ("READ TRACK INFO failed"); - /* Fallback to formatted toc */ - return 0; - } - - track_start = BRASERO_GET_32 (track_info.start_lba); - BRASERO_BURN_LOG ("comparing DCB %i and LBA %i to real start address %i", - start_BCD, start_LBA, track_start); - - /* try to find a conclusive match */ - if (track_start == start_BCD && track_start != start_LBA) - return -1; - - if (track_start == start_LBA && track_start != start_BCD) - return 1; - } - - /* Our last chance, the leadout. - * NOTE: no need to remove 150 sectors here. */ - start_BCD = BRASERO_MSF_TO_LBA (BRASERO_GET_BCD (desc [leadout].min), - BRASERO_GET_BCD (desc [leadout].sec), - BRASERO_GET_BCD (desc [leadout].frame)); - - start_LBA = BRASERO_MSF_TO_LBA (desc [leadout].min, - desc [leadout].sec, - desc [leadout].frame); - - BRASERO_BURN_LOG ("Comparing to track information from READ TRACK INFO for leadout"); - - size = 36; - - /* leadout number is number of tracks + 1 */ - result = brasero_mmc1_read_track_info (fd, - track_num + 1, - &track_info, - &size, - code); - - if (result != BRASERO_SCSI_OK) { - BRASERO_BURN_LOG ("READ TRACK INFO failed for leadout"); - /* Fallback to formatted toc */ - return 0; - } - - track_start = BRASERO_GET_32 (track_info.start_lba); - BRASERO_BURN_LOG ("comparing DCB %i and LBA %i to real start address %i", - start_BCD, start_LBA, track_start); - - /* try to find a conclusive match */ - if (track_start == start_BCD && track_start != start_LBA) - return -1; - - if (track_start == start_LBA && track_start != start_BCD) - return 1; - - /* fallback to formatted toc */ - return 0; -} - -/** - * The reason why we use this perhaps more lengthy method is that with - * multisession discs, the first track is reported to be two sectors shorter - * than it should. As I don't know why and since the following works we use - * this one. */ -static BraseroBurnResult -brasero_medium_get_CD_sessions_info (BraseroMedium *self, - int fd, - BraseroScsiErrCode *code) -{ - gint use_bcd; - GSList *iter; - int num, i, size; - gint leadout_start = 0; - BraseroScsiResult result; - BraseroMediumPrivate *priv; - BraseroScsiRawTocDesc *desc; - BraseroScsiRawTocData *toc = NULL; - - BRASERO_BURN_LOG ("Reading Raw Toc"); - - priv = BRASERO_MEDIUM_PRIVATE (self); - - size = 0; - result = brasero_mmc1_read_toc_raw (fd, - 0, - &toc, - &size, - code); - if (result != BRASERO_SCSI_OK) { - BRASERO_BURN_LOG ("READ TOC failed"); - return BRASERO_BURN_ERR; - } - - num = (size - sizeof (BraseroScsiRawTocData)) / - sizeof (BraseroScsiRawTocDesc); - - BRASERO_BURN_LOG ("%i track(s) found", num); - - desc = toc->desc; - use_bcd = brasero_medium_check_BCD_use (self, fd, desc, num, code); - if (!use_bcd) { - g_free (toc); - - BRASERO_BURN_LOG ("Fallback to formatted toc"); - return BRASERO_BURN_ERR; - } - - if (use_bcd > 0) - use_bcd = 0; - - if (use_bcd) { - BRASERO_BURN_LOG ("Using BCD format"); - } - else { - BRASERO_BURN_LOG ("Using HEX format"); - } - - for (i = 0; i < num; i++, desc ++) { - BraseroMediumTrack *track; - - track = NULL; - if (desc->adr == 1 && desc->point <= BRASERO_SCSI_Q_SUB_CHANNEL_TRACK_START) { - track = g_new0 (BraseroMediumTrack, 1); - track->session = desc->session_num; - - brasero_medium_set_track_type (self, track, desc->control); - if (use_bcd) - track->start = BRASERO_MSF_TO_LBA (BRASERO_GET_BCD (desc->p_min), - BRASERO_GET_BCD (desc->p_sec), - BRASERO_GET_BCD (desc->p_frame)); - else - track->start = BRASERO_MSF_TO_LBA (desc->p_min, - desc->p_sec, - desc->p_frame); - - track->start -= 150; - - /* if there are tracks and the last previously added track is in - * the same session then set the size */ - if (priv->tracks) { - BraseroMediumTrack *last_track; - - last_track = priv->tracks->data; - if (last_track->session == track->session) - last_track->blocks_num = track->start - last_track->start; - } - - priv->tracks = g_slist_prepend (priv->tracks, track); - } - else if (desc->point == BRASERO_SCSI_Q_SUB_CHANNEL_LEADOUT_START) { - /* NOTE: the leadout session is first in the list. So if - * we have tracks in the list set the last session track - * size when we reach a new leadout (and therefore a new - * session). */ - - if (priv->tracks) { - BraseroMediumTrack *last_track; - - last_track = priv->tracks->data; - last_track->blocks_num = leadout_start - last_track->start; - } - - if (use_bcd) - leadout_start = BRASERO_MSF_TO_LBA (BRASERO_GET_BCD (desc->p_min), - BRASERO_GET_BCD (desc->p_sec), - BRASERO_GET_BCD (desc->p_frame)); - else - leadout_start = BRASERO_MSF_TO_LBA (desc->p_min, - desc->p_sec, - desc->p_frame); - leadout_start -= 150; - } - } - - if (priv->tracks) { - BraseroMediumTrack *last_track; - - /* set the last found track size */ - last_track = priv->tracks->data; - last_track->blocks_num = leadout_start - last_track->start; - } - - /* Add a leadout */ - if (!(priv->info & BRASERO_MEDIUM_CLOSED)) { - BraseroMediumTrack *track; - - /* we shouldn't request info on leadout if the disc is closed */ - track = g_new0 (BraseroMediumTrack, 1); - priv->tracks = g_slist_prepend (priv->tracks, track); - track->start = leadout_start; - track->type = BRASERO_MEDIUM_TRACK_LEADOUT; - - brasero_medium_track_get_info (self, track, g_slist_length (priv->tracks), fd, code); - } - - priv->tracks = g_slist_reverse (priv->tracks); - - for (iter = priv->tracks; iter; iter = iter->next) { - BraseroMediumTrack *track; - - track = iter->data; - - /* check for tracks less that 300 sectors */ - if (track->blocks_num <= 300 && track->type != BRASERO_MEDIUM_TRACK_LEADOUT) { - BRASERO_BURN_LOG ("300 sectors size. Checking for real size"); - brasero_medium_track_volume_size (self, track, fd); - } - - BRASERO_BURN_LOG ("Track %i: type = %i start = %llu size = %llu", - g_slist_index (priv->tracks, track), - track->type, - track->start, - track->blocks_num); - } - - g_free (toc); - return BRASERO_BURN_OK; -} - -/** - * NOTE: for DVD-R multisession we lose 28688 blocks for each session - * so the capacity is the addition of all session sizes + 28688 for each - * For all multisession DVD-/+R and CDR-RW the remaining size is given - * in the leadout. One exception though with DVD+/-RW. - */ - -static void -brasero_medium_add_DVD_plus_RW_leadout (BraseroMedium *self, - gint32 start) -{ - BraseroMediumTrack *leadout; - BraseroMediumPrivate *priv; - - priv = BRASERO_MEDIUM_PRIVATE (self); - - leadout = g_new0 (BraseroMediumTrack, 1); - priv->tracks = g_slist_append (priv->tracks, leadout); - - leadout->start = start; - leadout->type = BRASERO_MEDIUM_TRACK_LEADOUT; - - /* we fabricate the leadout here. We don't really need one in - * fact since it is always at the last sector whatever the - * amount of data written. So we need in fact to read the file - * system and get the last sector from it. Hopefully it won't be - * buggy */ - priv->next_wr_add = 0; - - leadout->blocks_num = priv->block_num; - if (g_slist_length (priv->tracks) > 1) { - BraseroMediumTrack *track; - - track = priv->tracks->data; - leadout->blocks_num -= ((track->blocks_num > 300) ? track->blocks_num : 300); - } - BRASERO_BURN_LOG ("Adding fabricated leadout start = %llu length = %llu", - leadout->start, - leadout->blocks_num); -} - -static BraseroBurnResult -brasero_medium_get_sessions_info (BraseroMedium *self, - int fd, - BraseroScsiErrCode *code) -{ - int num, i, size; - BraseroScsiResult result; - BraseroScsiTocDesc *desc; - BraseroMediumPrivate *priv; - BraseroScsiFormattedTocData *toc = NULL; - - BRASERO_BURN_LOG ("Reading Toc"); - - priv = BRASERO_MEDIUM_PRIVATE (self); - result = brasero_mmc1_read_toc_formatted (fd, - 0, - &toc, - &size, - code); - if (result != BRASERO_SCSI_OK) { - g_free (toc); - - BRASERO_BURN_LOG ("READ TOC failed"); - return BRASERO_BURN_ERR; - } - - num = (size - sizeof (BraseroScsiFormattedTocData)) / - sizeof (BraseroScsiTocDesc); - - BRASERO_BURN_LOG ("%i track(s) found", num); - - desc = toc->desc; - for (i = 0; i < num; i ++, desc ++) { - BraseroMediumTrack *track; - - if (desc->track_num == BRASERO_SCSI_TRACK_LEADOUT_START) - break; - - track = g_new0 (BraseroMediumTrack, 1); - priv->tracks = g_slist_prepend (priv->tracks, track); - track->start = BRASERO_GET_32 (desc->track_start); - - /* we shouldn't request info on a track if the disc is closed */ - brasero_medium_track_get_info (self, - track, - g_slist_length (priv->tracks), - fd, - code); - - if (desc->control & BRASERO_SCSI_TRACK_COPY) - track->type |= BRASERO_MEDIUM_TRACK_COPY; - - if (!(desc->control & BRASERO_SCSI_TRACK_DATA)) { - track->type |= BRASERO_MEDIUM_TRACK_AUDIO; - priv->info |= BRASERO_MEDIUM_HAS_AUDIO; - - if (desc->control & BRASERO_SCSI_TRACK_PREEMP) - track->type |= BRASERO_MEDIUM_TRACK_PREEMP; - - if (desc->control & BRASERO_SCSI_TRACK_4_CHANNELS) - track->type |= BRASERO_MEDIUM_TRACK_4_CHANNELS; - } - else if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DVDRW_PLUS) - || BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DVDRW_RESTRICTED)) { - BraseroBurnResult result; - - /* a special case for these two kinds of media (DVD+RW) - * which have only one track: the first. */ - result = brasero_medium_track_volume_size (self, - track, - fd); - if (result == BRASERO_BURN_OK) { - track->type |= BRASERO_MEDIUM_TRACK_DATA; - priv->info |= BRASERO_MEDIUM_HAS_DATA; - - priv->next_wr_add = 0; - - if (desc->control & BRASERO_SCSI_TRACK_DATA_INCREMENTAL) - track->type |= BRASERO_MEDIUM_TRACK_INCREMENTAL; - } - else { - priv->tracks = g_slist_remove (priv->tracks, track); - g_free (track); - - priv->info |= BRASERO_MEDIUM_BLANK; - priv->info &= ~BRASERO_MEDIUM_CLOSED; - } - } - else { - track->type |= BRASERO_MEDIUM_TRACK_DATA; - priv->info |= BRASERO_MEDIUM_HAS_DATA; - - if (desc->control & BRASERO_SCSI_TRACK_DATA_INCREMENTAL) - track->type |= BRASERO_MEDIUM_TRACK_INCREMENTAL; - } - } - - /* put the tracks in the right order */ - priv->tracks = g_slist_reverse (priv->tracks); - - if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DVDRW_PLUS) - || BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DVDRW_RESTRICTED)) - brasero_medium_add_DVD_plus_RW_leadout (self, BRASERO_GET_32 (desc->track_start)); - else if (!(priv->info & BRASERO_MEDIUM_CLOSED)) { - BraseroMediumTrack *track; - - /* we shouldn't request info on leadout if the disc is closed - * (except for DVD+/- (restricted) RW (see above) */ - track = g_new0 (BraseroMediumTrack, 1); - priv->tracks = g_slist_append (priv->tracks, track); - track->start = BRASERO_GET_32 (desc->track_start); - track->type = BRASERO_MEDIUM_TRACK_LEADOUT; - - brasero_medium_track_get_info (self, - track, - g_slist_length (priv->tracks), - fd, - code); - } - - g_free (toc); - - return BRASERO_BURN_OK; -} - -static BraseroBurnResult -brasero_medium_get_contents (BraseroMedium *self, - int fd, - BraseroScsiErrCode *code) -{ - int size; - BraseroScsiResult result; - BraseroMediumPrivate *priv; - BraseroScsiDiscInfoStd *info = NULL; - - BRASERO_BURN_LOG ("Retrieving media status"); - - priv = BRASERO_MEDIUM_PRIVATE (self); - - result = brasero_mmc1_read_disc_information_std (fd, - &info, - &size, - code); - if (result != BRASERO_SCSI_OK) { - g_free (info); - - BRASERO_BURN_LOG ("READ DISC INFORMATION failed"); - return BRASERO_BURN_ERR; - } - - if (info->erasable) - priv->info |= BRASERO_MEDIUM_REWRITABLE; - - if (info->status == BRASERO_SCSI_DISC_EMPTY) { - BraseroMediumTrack *track; - - BRASERO_BURN_LOG ("Empty media"); - - priv->info |= BRASERO_MEDIUM_BLANK; - priv->block_size = 2048; - - if (BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DVDRW_PLUS) - || BRASERO_MEDIUM_IS (priv->info, BRASERO_MEDIUM_DVDRW_RESTRICTED)) - brasero_medium_add_DVD_plus_RW_leadout (self, 0); - else { - track = g_new0 (BraseroMediumTrack, 1); - track->start = 0; - track->type = BRASERO_MEDIUM_TRACK_LEADOUT; - priv->tracks = g_slist_prepend (priv->tracks, track); - - brasero_medium_track_get_info (self, - track, - 1, - fd, - code); - } - goto end; - } - - if (info->status == BRASERO_SCSI_DISC_INCOMPLETE) { - priv->info |= BRASERO_MEDIUM_APPENDABLE; - BRASERO_BURN_LOG ("Appendable media"); - } - else if (info->status == BRASERO_SCSI_DISC_FINALIZED) { - priv->info |= BRASERO_MEDIUM_CLOSED; - BRASERO_BURN_LOG ("Closed media"); - } - - if (priv->info & BRASERO_MEDIUM_CD) { - result = brasero_medium_get_CD_sessions_info (self, fd, code); - if (result != BRASERO_BURN_OK) - result = brasero_medium_get_sessions_info (self, fd, code); - } - else - result = brasero_medium_get_sessions_info (self, fd, code); - - if (result != BRASERO_BURN_OK) - goto end; - -end: - - g_free (info); - return BRASERO_BURN_OK; -} - -static void -brasero_medium_init_real (BraseroMedium *object, int fd) -{ - gchar *name; - BraseroBurnResult result; - BraseroMediumPrivate *priv; - BraseroScsiErrCode code = 0; - - priv = BRASERO_MEDIUM_PRIVATE (object); - - name = nautilus_burn_drive_get_name_for_display (priv->drive); - BRASERO_BURN_LOG ("Initializing information for medium in %s", name); - g_free (name); - - result = brasero_medium_get_medium_type (object, fd, &code); - if (result != BRASERO_BURN_OK) - return; - - brasero_medium_get_capacity_by_type (object, fd, &code); - - result = brasero_medium_get_contents (object, fd, &code); - if (result != BRASERO_BURN_OK) - return; - - /* assume that css feature is only for DVD-ROM which might be wrong but - * some drives wrongly reports that css is enabled for blank DVD+R/W */ - if (BRASERO_MEDIUM_IS (priv->info, (BRASERO_MEDIUM_DVD|BRASERO_MEDIUM_ROM))) - brasero_medium_get_css_feature (object, fd, &code); - - BRASERO_BURN_LOG_DISC_TYPE (priv->info, "media is "); -} - -static gboolean -brasero_medium_retry_open (gpointer object) -{ - int fd; - const gchar *path; - BraseroMedium *self; - BraseroMediumPrivate *priv; - - self = BRASERO_MEDIUM (object); - priv = BRASERO_MEDIUM_PRIVATE (object); - path = nautilus_burn_drive_get_device (priv->drive); - - BRASERO_BURN_LOG ("Retrying to open device %s", path); - fd = open (path, OPEN_FLAGS); - if (fd < 0) { - if (errno == EBUSY - || errno == EAGAIN - || errno == EWOULDBLOCK) { - BRASERO_BURN_LOG ("Device busy"); - /* we'll retry in a second */ - return TRUE; - } - - BRASERO_BURN_LOG ("Open () failed"); - priv->info = BRASERO_MEDIUM_UNSUPPORTED; - priv->retry_id = 0; - return FALSE; - } - - BRASERO_BURN_LOG ("Open () succeeded\n"); - priv->info = BRASERO_MEDIUM_NONE; - priv->icon = icons [0]; - - priv->retry_id = 0; - - brasero_medium_init_real (self, fd); - close (fd); - - return FALSE; -} - -static void -brasero_medium_try_open (BraseroMedium *self) -{ - int fd; - const gchar *path; - BraseroMediumPrivate *priv; - - priv = BRASERO_MEDIUM_PRIVATE (self); - path = nautilus_burn_drive_get_device (priv->drive); - - /* the drive might be busy (a burning is going on) so we don't block - * but we re-try to open it every second */ - BRASERO_BURN_LOG ("Trying to open device %s", path); - fd = open (path, OPEN_FLAGS); - if (fd < 0) { - if (errno == EAGAIN - || errno == EWOULDBLOCK - || errno == EBUSY) { - BRASERO_BURN_LOG ("Device busy"); - priv->info = BRASERO_MEDIUM_BUSY; - priv->icon = icons [0]; - - priv->retry_id = g_timeout_add (BUSY_RETRY_TIME, - brasero_medium_retry_open, - self); - } - - BRASERO_BURN_LOG ("Open () failed"); - return; - } - - BRASERO_BURN_LOG ("Open () succeeded"); - brasero_medium_init_real (self, fd); - close (fd); -} - -static void -brasero_medium_init (BraseroMedium *object) -{ - BraseroMediumPrivate *priv; - - priv = BRASERO_MEDIUM_PRIVATE (object); - priv->next_wr_add = -1; - - /* we can't do anything here since properties haven't been set yet */ -} - -static void -brasero_medium_finalize (GObject *object) -{ - BraseroMediumPrivate *priv; - - priv = BRASERO_MEDIUM_PRIVATE (object); - - if (priv->retry_id) { - g_source_remove (priv->retry_id); - priv->retry_id = 0; - } - - g_free (priv->rd_speeds); - priv->rd_speeds = NULL; - - g_free (priv->wr_speeds); - priv->wr_speeds = NULL; - - g_slist_foreach (priv->tracks, (GFunc) g_free, NULL); - g_slist_free (priv->tracks); - priv->tracks = NULL; - - nautilus_burn_drive_unref (priv->drive); - priv->drive = NULL; - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -brasero_medium_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) -{ - BraseroMediumPrivate *priv; - - g_return_if_fail (BRASERO_IS_MEDIUM (object)); - - priv = BRASERO_MEDIUM_PRIVATE (object); - - switch (prop_id) - { - case PROP_DRIVE: - priv->drive = g_value_get_object (value); - nautilus_burn_drive_ref (priv->drive); - brasero_medium_try_open (BRASERO_MEDIUM (object)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -brasero_medium_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - BraseroMediumPrivate *priv; - - g_return_if_fail (BRASERO_IS_MEDIUM (object)); - - priv = BRASERO_MEDIUM_PRIVATE (object); - - switch (prop_id) - { - case PROP_DRIVE: - nautilus_burn_drive_ref (priv->drive); - g_value_set_object (value, priv->drive); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -brasero_medium_class_init (BraseroMediumClass *klass) -{ - GObjectClass* object_class = G_OBJECT_CLASS (klass); - parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass)); - - g_type_class_add_private (klass, sizeof (BraseroMediumPrivate)); - - object_class->finalize = brasero_medium_finalize; - object_class->set_property = brasero_medium_set_property; - object_class->get_property = brasero_medium_get_property; - - g_object_class_install_property (object_class, - PROP_DRIVE, - g_param_spec_object ("drive", - "drive", - "drive in which medium is inserted", - NAUTILUS_BURN_TYPE_DRIVE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); -} - -GType -brasero_medium_get_type (void) -{ - static GType our_type = 0; - - if (our_type == 0) - { - static const GTypeInfo our_info = - { - sizeof (BraseroMediumClass), /* class_size */ - (GBaseInitFunc) NULL, /* base_init */ - (GBaseFinalizeFunc) NULL, /* base_finalize */ - (GClassInitFunc) brasero_medium_class_init, /* class_init */ - (GClassFinalizeFunc) NULL, /* class_finalize */ - NULL /* class_data */, - sizeof (BraseroMedium), /* instance_size */ - 0, /* n_preallocs */ - (GInstanceInitFunc) brasero_medium_init, /* instance_init */ - NULL /* value_table */ - }; - - our_type = g_type_register_static (G_TYPE_OBJECT, "BraseroMedium", - &our_info, 0); - } - - return our_type; -} - -BraseroMedium * -brasero_medium_new (NautilusBurnDrive *drive) -{ - g_return_val_if_fail (drive != NULL, NULL); - return BRASERO_MEDIUM (g_object_new (BRASERO_TYPE_MEDIUM, - "drive", drive, - NULL)); -}