/* Private */ int UDFReadBlocksRaw( dvd_reader_t *device, uint32_t lb_number, size_t block_count, unsigned char *data, int encrypted ) { int ret; ret = dvdcss_seek( device->fd, (int) lb_number, DVDCSS_SEEK_KEY ); if( ret != (int) lb_number ) { //fprintf( stderr, "libdvdread: Can't seek to block %u\n", lb_number ); return 0; } return dvdcss_read( device->fd, (char *) data, (int) block_count, encrypted ); }
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; }
static gboolean brasero_dvdcss_create_scrambled_sectors_map (BraseroDvdcss *self, BraseroDrive *drive, GQueue *map, dvdcss_handle *handle, BraseroVolFile *parent, GError **error) { GList *iter; /* this allows to cache keys for encrypted files */ for (iter = parent->specific.dir.children; iter; iter = iter->next) { BraseroVolFile *file; file = iter->data; if (!file->isdir) { if (!strncmp (file->name + strlen (file->name) - 6, ".VOB", 4)) { BraseroScrambledSectorRange *range; gsize current_extent; GSList *extents; BRASERO_JOB_LOG (self, "Retrieving keys for %s", file->name); /* take the first address for each extent of the file */ if (!file->specific.file.extents) { BRASERO_JOB_LOG (self, "Problem: file has no extents"); return FALSE; } range = g_new0 (BraseroScrambledSectorRange, 1); for (extents = file->specific.file.extents; extents; extents = extents->next) { BraseroVolFileExtent *extent; extent = extents->data; range->start = extent->block; range->end = extent->block + BRASERO_BYTES_TO_SECTORS (extent->size, DVDCSS_BLOCK_SIZE); BRASERO_JOB_LOG (self, "From 0x%llx to 0x%llx", range->start, range->end); g_queue_push_head (map, range); if (extent->size == 0) { BRASERO_JOB_LOG (self, "0 size extent"); continue; } current_extent = dvdcss_seek (handle, range->start, DVDCSS_SEEK_KEY); if (current_extent != range->start) { BRASERO_JOB_LOG (self, "Problem: could not retrieve key"); g_set_error (error, BRASERO_BURN_ERROR, BRASERO_BURN_ERROR_GENERAL, /* Translators: %s is the path to a drive. "regionset %s" * should be left as is just like "DVDCSS_METHOD=title * brasero --no-existing-session" */ _("Error while retrieving a key used for encryption. You may solve such a problem with one of the following methods: in a terminal either set the proper DVD region code for your CD/DVD player with the \"regionset %s\" command or run the \"DVDCSS_METHOD=title brasero --no-existing-session\" command"), brasero_drive_get_device (drive)); return FALSE; } } } } else if (!brasero_dvdcss_create_scrambled_sectors_map (self, drive, map, handle, file, error)) return FALSE; } return TRUE; }
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; }