shithub: libdvdcss

Download patch

ref: ec1bd09bf4768c9641363c13af2248edd0e24c91
parent: c8e2bf595185afd6835852e78e2318e9c9cbc049
author: Sam Hocevar <sam@videolan.org>
date: Sun Nov 24 12:34:23 EST 2002

* ./src/css.c, ./src/libdvdcss.c: applied a 
    to cache title keys on disk.


--- a/src/css.c
+++ b/src/css.c
@@ -2,7 +2,7 @@
  * css.c: Functions for DVD authentication and descrambling
  *****************************************************************************
  * Copyright (C) 1999-2001 VideoLAN
- * $Id: css.c,v 1.19 2002/11/14 12:38:57 gbazin Exp $
+ * $Id: css.c,v 1.20 2002/11/24 17:34:23 sam Exp $
  *
  * Author: St�phane Borel <stef@via.ecp.fr>
  *         H�kan Hjort <d95hjort@dtek.chalmers.se>
@@ -38,6 +38,10 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <fcntl.h>
 
 #include "dvdcss/dvdcss.h"
 
@@ -275,10 +279,11 @@
  *****************************************************************************/
 int _dvdcss_title ( dvdcss_t dvdcss, int i_block )
 {
+    char *       psz_cachefile = NULL;
     dvd_title_t *p_title;
     dvd_title_t *p_newtitle;
     dvd_key_t    p_title_key;
-    int          i_ret;
+    int          i_fd, i_ret = -1, b_cache = 0;
 
     if( ! dvdcss->b_scrambled )
     {
@@ -302,18 +307,54 @@
         return 0;
     }
 
-    /* Crack or decrypt CSS title key for current VTS */
-    i_ret = _dvdcss_titlekey( dvdcss, i_block, p_title_key );
+    /* Check whether the key is in our disk cache */
+    if( dvdcss->psz_cachefile[0] )
+    {
+        /* XXX: be careful, we use sprintf and not snprintf */
+        sprintf( dvdcss->psz_block, "%0.10x", i_block );
+        i_fd = open( dvdcss->psz_cachefile, O_RDONLY );
+        b_cache = 1;
 
+        if( i_fd >= 0 )
+        {
+            if( read( i_fd, p_title_key, 5 ) == 5 )
+            {
+                _dvdcss_debug( dvdcss, "key found in cache" );
+                /* Don't try to save it again */
+                b_cache = 0;
+                i_ret = 1;
+            }
+            close( i_fd );
+        }
+    }
+
+    /* Crack or decrypt CSS title key for current VTS */
     if( i_ret < 0 )
     {
-        _dvdcss_error( dvdcss, "fatal error in vts css key" );
-        return i_ret;
+        i_ret = _dvdcss_titlekey( dvdcss, i_block, p_title_key );
+
+        if( i_ret < 0 )
+        {
+            _dvdcss_error( dvdcss, "fatal error in vts css key" );
+            return i_ret;
+        }
+
+        if( i_ret == 0 )
+        {
+            _dvdcss_debug( dvdcss, "unencrypted title" );
+            /* We cache this anyway, so we don't need to check again. */
+        }
     }
-    else if( i_ret == 0 )
+
+    /* Key is valid, we store it on disk. */
+    if( b_cache )
     {
-        _dvdcss_debug( dvdcss, "unencrypted title" );
-        /* Still store this in the cache, so we don't need to check again. */
+        i_fd = open( dvdcss->psz_cachefile, O_RDWR|O_CREAT|O_EXCL, 0644 );
+        if( i_fd >= 0 )
+        {
+            write( i_fd, p_title_key, 5 );
+            close( i_fd );
+        }
     }
 
     /* Find our spot in the list */
@@ -1451,7 +1492,7 @@
         return 1;
     }
 
-    if( i_encrypted == 0 )
+    if( i_encrypted == 0 && i_reads > 0 )
     {
         memset( p_titlekey, 0, KEY_SIZE );
         _dvdcss_debug( dvdcss, "file was unscrambled" );
--- a/src/device.c
+++ b/src/device.c
@@ -2,7 +2,7 @@
  * device.h: DVD device access
  *****************************************************************************
  * Copyright (C) 1998-2002 VideoLAN
- * $Id: device.c,v 1.6 2002/10/19 09:53:33 gbazin Exp $
+ * $Id: device.c,v 1.7 2002/11/24 17:34:23 sam Exp $
  *
  * Authors: St�phane Borel <stef@via.ecp.fr>
  *          Samuel Hocevar <sam@zoy.org>
@@ -33,6 +33,7 @@
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/param.h>
 #include <fcntl.h>
 
 #ifdef HAVE_UNISTD_H
--- a/src/error.c
+++ b/src/error.c
@@ -2,7 +2,7 @@
  * error.c: error management functions
  *****************************************************************************
  * Copyright (C) 1998-2002 VideoLAN
- * $Id: error.c,v 1.2 2002/08/10 14:27:26 sam Exp $
+ * $Id: error.c,v 1.3 2002/11/24 17:34:23 sam Exp $
  *
  * Author: Samuel Hocevar <sam@zoy.org>
  *
@@ -24,6 +24,7 @@
 #include "config.h"
 
 #include <stdio.h>
+#include <sys/param.h>
 
 #include "dvdcss/dvdcss.h"
 
--- a/src/libdvdcss.c
+++ b/src/libdvdcss.c
@@ -5,7 +5,7 @@
  *          H�kan Hjort <d95hjort@dtek.chalmers.se>
  *
  * Copyright (C) 1998-2002 VideoLAN
- * $Id: libdvdcss.c,v 1.19 2002/10/18 18:48:59 sam Exp $
+ * $Id: libdvdcss.c,v 1.20 2002/11/24 17:34:23 sam Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -79,6 +79,11 @@
  *
  * \li \b DVDCSS_RAW_DEVICE: specify the raw device to use.
  * 
+ * \li \b DVDCSS_CACHE: specify a directory in which to store title key
+ *     values. This will speed up descrambling of DVDs which are in the
+ *     cache. The DVDCSS_CACHE directory is created if it does not exist,
+ *     and a subdirectory is created named after the DVD's title or
+ *     manufacturing date.
  */
 
 /*
@@ -91,7 +96,9 @@
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/param.h>
 #include <fcntl.h>
+#include <errno.h>
 
 #ifdef HAVE_UNISTD_H
 #   include <unistd.h>
@@ -137,6 +144,7 @@
 
     char *psz_method = getenv( "DVDCSS_METHOD" );
     char *psz_verbose = getenv( "DVDCSS_VERBOSE" );
+    char *psz_cache = getenv( "DVDCSS_CACHE" );
 #ifndef WIN32
     char *psz_raw_device = getenv( "DVDCSS_RAW_DEVICE" );
 #endif
@@ -162,6 +170,7 @@
     dvdcss->psz_device = (char *)strdup( psz_target );
     dvdcss->psz_error = "no error";
     dvdcss->i_method = DVDCSS_METHOD_KEY;
+    dvdcss->psz_cachefile[0] = '\0';
     dvdcss->b_debug = 0;
     dvdcss->b_errors = 0;
 
@@ -209,6 +218,23 @@
     }
 
     /*
+     *  Find cache dir from the DVDCSS_CACHE environment variable
+     */
+    if( psz_cache != NULL )
+    {
+        if( psz_cache[0] == '\0' )
+        {
+            psz_cache = NULL;
+        }
+        /* Check that we can add the ID directory and the block filename */
+        else if( strlen( psz_cache ) + 1 + 32 + 1 + 10 + 1 > PATH_MAX )
+        {
+            _dvdcss_error( dvdcss, "cache directory name is too long" );
+            psz_cache = NULL;
+        }
+    }
+
+    /*
      *  Open device
      */
     i_ret = _dvdcss_open( dvdcss );
@@ -260,6 +286,99 @@
         _dvdcss_raw_open( dvdcss, psz_raw_device );
     }
 #endif
+
+    /* If the cache is enabled, extract a unique disc ID */
+    if( psz_cache )
+    {
+        u8  p_sector[DVDCSS_BLOCK_SIZE];
+        unsigned char   psz_debug[PATH_MAX+30];
+        unsigned char * psz_data;
+        int i;
+
+        /* The data we are looking for is at sector 16 (32768 bytes):
+         *  - offset 40: disc title (32 uppercase chars)
+         *  - offset 813: manufacturing date + serial no (16 digits) */
+
+        i_ret = dvdcss->pf_seek( dvdcss, 16 );
+        if( i_ret != 16 )
+        {
+            goto nocache;
+        }
+
+        i_ret = dvdcss->pf_read( dvdcss, p_sector, 1 );
+        if( i_ret != 1 )
+        {
+            goto nocache;
+        }
+
+        /* Get the disc title */
+        psz_data = p_sector + 40;
+        psz_data[32] = '\0';
+
+        for( i = 0 ; i < 32 ; i++ )
+        {
+            if( psz_data[i] <= ' ' )
+            {
+                psz_data[i] = '\0';
+                break;
+            }
+            else if( psz_data[i] == '/' || psz_data[i] == '\\' )
+            {
+                psz_data[i] = '-';
+            }
+        }
+
+        /* If it's not long enough, try the date + serial */
+        if( strlen( psz_data ) < 6 )
+        {
+            psz_data = p_sector + 813;
+            psz_data[16] = '\0';
+
+            /* Check that all characters are digits, otherwise convert. */
+            for( i = 0 ; i < 16 ; i++ )
+            {
+                if( psz_data[i] < '0' || psz_data[i] > '9' )
+                {
+                    sprintf( psz_data,
+                             "%0.2X%0.2X%0.2X%0.2X%0.2X%0.2X%0.2X%0.2X",
+                             psz_data[0], psz_data[1], psz_data[2],
+                             psz_data[3], psz_data[4], psz_data[5],
+                             psz_data[6], psz_data[7] );
+                    break;
+                }
+            }
+        }
+
+        /* We have a disc name or ID, we can create the cache dir */
+        i = sprintf( dvdcss->psz_cachefile, "%s", psz_cache );
+        i_ret = mkdir( dvdcss->psz_cachefile, 0755 );
+        if( i_ret < 0 && errno != EEXIST )
+        {
+            _dvdcss_error( dvdcss, "failed creating cache directory" );
+            dvdcss->psz_cachefile[0] = '\0';
+            goto nocache;
+        }
+
+        i += sprintf( dvdcss->psz_cachefile + i, "/%s/", psz_data );
+        i_ret = mkdir( dvdcss->psz_cachefile, 0755 );
+        if( i_ret < 0 && errno != EEXIST )
+        {
+            _dvdcss_error( dvdcss, "failed creating cache subdirectory" );
+            dvdcss->psz_cachefile[0] = '\0';
+            goto nocache;
+        }
+
+        /* Pointer to the filename we will use. */
+        dvdcss->psz_block = dvdcss->psz_cachefile + i;
+
+        sprintf( psz_debug, "using CSS key cache dir: %s",
+                            dvdcss->psz_cachefile );
+        _dvdcss_debug( dvdcss, psz_debug );
+    }
+    nocache:
+
+    /* Seek at the beginning, just for safety. */
+    dvdcss->pf_seek( dvdcss, 0 );
 
     return dvdcss;
 }
--- a/src/libdvdcss.h
+++ b/src/libdvdcss.h
@@ -2,7 +2,7 @@
  * private.h: private DVD reading library data
  *****************************************************************************
  * Copyright (C) 1998-2001 VideoLAN
- * $Id: libdvdcss.h,v 1.5 2002/10/18 18:48:59 sam Exp $
+ * $Id: libdvdcss.h,v 1.6 2002/11/24 17:34:23 sam Exp $
  *
  * Authors: St�phane Borel <stef@via.ecp.fr>
  *          Samuel Hocevar <sam@zoy.org>
@@ -46,6 +46,10 @@
     int          b_ioctls;
     int          b_scrambled;
     dvd_title_t *p_titles;
+
+    /* Key cache directory and pointer to the filename */
+    char   psz_cachefile[PATH_MAX];
+    char * psz_block;
 
     /* Error management */
     char * psz_error;