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; }
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; }