/**
* Close a DVD block device file.
*/
void DVDClose( dvd_reader_t *dvd )
{
	if( dvd ) {
		if( dvd->fd ) dvdcss_close( dvd->fd );
		if( dvd->path_root ) free( dvd->path_root );
		free( dvd );
	}
}
Example #2
0
static gpointer
brasero_dvdcss_write_image_thread (gpointer data)
{
	guchar buf [DVDCSS_BLOCK_SIZE * BRASERO_DVDCSS_I_BLOCKS];
	BraseroScrambledSectorRange *range = NULL;
	BraseroMedium *medium = NULL;
	BraseroVolFile *files = NULL;
	dvdcss_handle *handle = NULL;
	BraseroDrive *drive = NULL;
	BraseroDvdcssPrivate *priv;
	gint64 written_sectors = 0;
	BraseroDvdcss *self = data;
	BraseroTrack *track = NULL;
	guint64 remaining_sectors;
	FILE *output_fd = NULL;
	BraseroVolSrc *vol;
	gint64 volume_size;
	GQueue *map = NULL;

	brasero_job_set_use_average_rate (BRASERO_JOB (self), TRUE);
	brasero_job_set_current_action (BRASERO_JOB (self),
					BRASERO_BURN_ACTION_ANALYSING,
					_("Retrieving DVD keys"),
					FALSE);
	brasero_job_start_progress (BRASERO_JOB (self), FALSE);

	priv = BRASERO_DVDCSS_PRIVATE (self);

	/* get the contents of the DVD */
	brasero_job_get_current_track (BRASERO_JOB (self), &track);
	drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));

	vol = brasero_volume_source_open_file (brasero_drive_get_device (drive), &priv->error);
	files = brasero_volume_get_files (vol,
					  0,
					  NULL,
					  NULL,
					  NULL,
					  &priv->error);
	brasero_volume_source_close (vol);
	if (!files)
		goto end;

	medium = brasero_drive_get_medium (drive);
	brasero_medium_get_data_size (medium, NULL, &volume_size);
	if (volume_size == -1) {
		priv->error = g_error_new (BRASERO_BURN_ERROR,
					   BRASERO_BURN_ERROR_GENERAL,
					   _("The size of the volume could not be retrieved"));
		goto end;
	}

	/* create a handle/open DVD */
	handle = dvdcss_open (brasero_drive_get_device (drive));
	if (!handle) {
		priv->error = g_error_new (BRASERO_BURN_ERROR,
					   BRASERO_BURN_ERROR_GENERAL,
					   _("Video DVD could not be opened"));
		goto end;
	}

	/* look through the files to get the ranges of encrypted sectors
	 * and cache the CSS keys while at it. */
	map = g_queue_new ();
	if (!brasero_dvdcss_create_scrambled_sectors_map (self, drive, map, handle, files, &priv->error))
		goto end;

	BRASERO_JOB_LOG (self, "DVD map created (keys retrieved)");

	g_queue_sort (map, brasero_dvdcss_sort_ranges, NULL);

	brasero_volume_file_free (files);
	files = NULL;

	if (dvdcss_seek (handle, 0, DVDCSS_NOFLAGS) < 0) {
		BRASERO_JOB_LOG (self, "Error initial seeking");
		priv->error = g_error_new (BRASERO_BURN_ERROR,
					   BRASERO_BURN_ERROR_GENERAL,
					   _("Error while reading video DVD (%s)"),
					   dvdcss_error (handle));
		goto end;
	}

	brasero_job_set_current_action (BRASERO_JOB (self),
					BRASERO_BURN_ACTION_DRIVE_COPY,
					_("Copying video DVD"),
					FALSE);

	brasero_job_start_progress (BRASERO_JOB (self), TRUE);

	remaining_sectors = volume_size;
	range = g_queue_pop_head (map);

	if (brasero_job_get_fd_out (BRASERO_JOB (self), NULL) != BRASERO_BURN_OK) {
		gchar *output = NULL;

		brasero_job_get_image_output (BRASERO_JOB (self), &output, NULL);
		output_fd = fopen (output, "w");
		if (!output_fd) {
			priv->error = g_error_new_literal (BRASERO_BURN_ERROR,
							   BRASERO_BURN_ERROR_GENERAL,
							   g_strerror (errno));
			g_free (output);
			goto end;
		}
		g_free (output);
	}

	while (remaining_sectors) {
		gint flag;
		guint64 num_blocks, data_size;

		if (priv->cancel)
			break;

		num_blocks = BRASERO_DVDCSS_I_BLOCKS;

		/* see if we are approaching the end of the dvd */
		if (num_blocks > remaining_sectors)
			num_blocks = remaining_sectors;

		/* see if we need to update the key */
		if (!range || written_sectors < range->start) {
			/* this is in a non scrambled sectors range */
			flag = DVDCSS_NOFLAGS;
	
			/* we don't want to mix scrambled and non scrambled sectors */
			if (range && written_sectors + num_blocks > range->start)
				num_blocks = range->start - written_sectors;
		}
		else {
			/* this is in a scrambled sectors range */
			flag = DVDCSS_READ_DECRYPT;

			/* see if we need to update the key */
			if (written_sectors == range->start) {
				int pos;

				pos = dvdcss_seek (handle, written_sectors, DVDCSS_SEEK_KEY);
				if (pos < 0) {
					BRASERO_JOB_LOG (self, "Error seeking");
					priv->error = g_error_new (BRASERO_BURN_ERROR,
								   BRASERO_BURN_ERROR_GENERAL,
								   _("Error while reading video DVD (%s)"),
								   dvdcss_error (handle));
					break;
				}
			}

			/* we don't want to mix scrambled and non scrambled sectors
			 * NOTE: range->end address is the next non scrambled sector */
			if (written_sectors + num_blocks > range->end)
				num_blocks = range->end - written_sectors;

			if (written_sectors + num_blocks == range->end) {
				/* update to get the next range of scrambled sectors */
				g_free (range);
				range = g_queue_pop_head (map);
			}
		}

		num_blocks = dvdcss_read (handle, buf, num_blocks, flag);
		if (num_blocks < 0) {
			BRASERO_JOB_LOG (self, "Error reading");
			priv->error = g_error_new (BRASERO_BURN_ERROR,
						   BRASERO_BURN_ERROR_GENERAL,
						   _("Error while reading video DVD (%s)"),
						   dvdcss_error (handle));
			break;
		}

		data_size = num_blocks * DVDCSS_BLOCK_SIZE;
		if (output_fd) {
			if (fwrite (buf, 1, data_size, output_fd) != data_size) {
                                int errsv = errno;

				priv->error = g_error_new (BRASERO_BURN_ERROR,
							   BRASERO_BURN_ERROR_GENERAL,
							   _("Data could not be written (%s)"),
							   g_strerror (errsv));
				break;
			}
		}
		else {
			BraseroBurnResult result;

			result = brasero_dvdcss_write_sector_to_fd (self,
								    buf,
								    data_size);
			if (result != BRASERO_BURN_OK)
				break;
		}

		written_sectors += num_blocks;
		remaining_sectors -= num_blocks;
		brasero_job_set_written_track (BRASERO_JOB (self), written_sectors * DVDCSS_BLOCK_SIZE);
	}

end:

	if (range)
		g_free (range);

	if (handle)
		dvdcss_close (handle);

	if (files)
		brasero_volume_file_free (files);

	if (output_fd)
		fclose (output_fd);

	if (map) {
		g_queue_foreach (map, (GFunc) g_free, NULL);
		g_queue_free (map);
	}

	if (!priv->cancel)
		priv->thread_id = g_idle_add (brasero_dvdcss_thread_finished, self);

	/* End thread */
	g_mutex_lock (priv->mutex);
	priv->thread = NULL;
	g_cond_signal (priv->cond);
	g_mutex_unlock (priv->mutex);

	g_thread_exit (NULL);

	return NULL;
}
Example #3
0
int main( int i_argc, char *ppsz_argv[] )
{
    dvdcss_t       dvdcss;
    unsigned char  p_data[ DVDCSS_BLOCK_SIZE * 2 ];
    unsigned char *p_buffer;
    unsigned int   i_sector;
    int            i_ret;

    /* Check for 2 arguments */
    if( i_argc != 3 )
    {
        printf( "usage: %s <target> <sector>\n", ppsz_argv[0] );
        printf( "examples:\n" );
        printf( "  %s /dev/hdc 1024\n", ppsz_argv[0] );
        printf( "  %s D: 1024\n", ppsz_argv[0] );
        printf( "  %s scrambledfile.vob 1024\n", ppsz_argv[0] );
        return -1;
    }

    /* Save the requested sector */
    i_sector = atoi( ppsz_argv[2] );

    /* Initialize libdvdcss */
    dvdcss = dvdcss_open( ppsz_argv[1] );
    if( dvdcss == NULL )
    {
        printf( "argh ! couldn't open DVD (%s)\n", ppsz_argv[1] );
        return -1;
    }

    /* Align our read buffer */
    p_buffer = p_data + DVDCSS_BLOCK_SIZE
                      - ((long int)p_data & (DVDCSS_BLOCK_SIZE-1));

    /* Set the file descriptor at sector i_sector and read one sector */
    i_ret = dvdcss_seek( dvdcss, i_sector, DVDCSS_NOFLAGS );
    if( i_ret != (int)i_sector )
    {
        printf( "seek failed (%s)\n", dvdcss_error( dvdcss ) );
        dvdcss_close( dvdcss );
        return i_ret;
    }

    i_ret = dvdcss_read( dvdcss, p_buffer, 1, DVDCSS_NOFLAGS );
    if( i_ret != 1 )
    {
        printf( "read failed (%s)\n", dvdcss_error( dvdcss ) );
        dvdcss_close( dvdcss );
        return i_ret;
    }

    /* Print the sector */
    printf( "requested sector: " );
    dumpsector( p_buffer );

    /* Check if sector was encrypted */
    if( isscrambled( p_buffer ) )
    {
        /* Set the file descriptor position to the previous location */
        /* ... and get the appropriate key for this sector */
        i_ret = dvdcss_seek( dvdcss, i_sector, DVDCSS_SEEK_KEY );
        if( i_ret != (int)i_sector )
        {
            printf( "seek failed (%s)\n", dvdcss_error( dvdcss ) );
            dvdcss_close( dvdcss );
            return i_ret;
        }

        /* Read sector again, and decrypt it on the fly */
        i_ret = dvdcss_read( dvdcss, p_buffer, 1, DVDCSS_READ_DECRYPT );
        if( i_ret != 1 )
        {
            printf( "read failed (%s)\n", dvdcss_error( dvdcss ) );
            dvdcss_close( dvdcss );
            return i_ret;
        }

        /* Print the decrypted sector */
        printf( "unscrambled sector: " );
        dumpsector( p_buffer );
    }
    else
    {
        printf( "sector is not scrambled\n" );
    }

    /* Close the device */
    i_ret = dvdcss_close( dvdcss );

    return i_ret;
}