rockbox/apps/plugins/md5sum.c

301 lines
7.9 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2008 Antoine Cellerier <dionoea -at- videolan -dot- org>
*
* 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 the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "plugin.h"
#include "lib/md5.h"
#define BUFFERSIZE 16384
static int count = 0;
static int done = 0;
static bool quit = false;
static int hash( char *string, const char *path )
{
static char buffer[BUFFERSIZE];
ssize_t len;
struct md5_s md5;
int in = rb->open( path, O_RDONLY );
if( in < 0 ) return -1;
InitMD5( &md5 );
while( !quit && ( len = rb->read( in, buffer, sizeof(buffer) ) ) > 0 )
{
AddMD5( &md5, buffer, len );
if( rb->get_action(CONTEXT_STD, TIMEOUT_NOBLOCK) == ACTION_STD_CANCEL )
quit = true;
}
EndMD5( &md5 );
psz_md5_hash( string, &md5 );
rb->close( in );
return 0;
}
static void hash_file( int out, const char *path )
{
if( out < 0 )
count++;
else
{
char string[MD5_STRING_LENGTH+1];
int status;
done++;
rb->splashf( 0, "%d / %d : %s", done, count, path );
status = hash( string, path );
if( quit )
return;
if( status )
rb->write( out, "error", 5 );
else
rb->write( out, string, MD5_STRING_LENGTH );
rb->write( out, " ", 2 );
rb->write( out, path, rb->strlen( path ) );
rb->write( out, "\n", 1 );
rb->yield();
}
}
static void hash_dir( int out, const char *path )
{
DIR *dir;
struct dirent *entry;
dir = rb->opendir( path );
if( dir )
{
while( !quit && ( entry = rb->readdir( dir ) ) )
{
char childpath[MAX_PATH];
rb->snprintf( childpath, MAX_PATH, "%s/%s",
rb->strcmp( path, "/" ) ? path : "", entry->d_name );
struct dirinfo info = rb->dir_get_info(dir, entry);
if (info.attribute & ATTR_DIRECTORY)
{
if( rb->strcmp( entry->d_name, "." )
&& rb->strcmp( entry->d_name, ".." ) )
{
/* Got a sub directory */
hash_dir( out, childpath );
}
}
else
{
/* Got a file */
hash_file( out, childpath );
}
}
rb->closedir( dir );
}
}
static void hash_list( int out, const char *path )
{
int list = rb->open( path, O_RDONLY );
char newpath[MAX_PATH];
if( list < 0 ) return;
while( !quit && rb->read_line( list, newpath, MAX_PATH ) > 0 )
{
DIR *dir = rb->opendir( newpath );
if( dir )
{
rb->closedir( dir );
hash_dir( out, newpath );
}
else
{
hash_file( out, newpath );
}
}
rb->close( list );
}
static void hash_check( int out, const char *path )
{
int list = rb->open( path, O_RDONLY );
char line[MD5_STRING_LENGTH+1+MAX_PATH+1];
int len;
if( list < 0 ) return;
while( !quit && ( len = rb->read_line( list, line, MD5_STRING_LENGTH+1+MAX_PATH+1 ) ) > 0 )
{
if( out < 0 )
count++;
else
{
const char *filename = rb->strchr( line, ' ' );
done++;
rb->splashf( 0, "%d / %d : %s", done, count, filename );
if( !filename || len < MD5_STRING_LENGTH + 2 )
{
const char error[] = "Malformed input line ... skipping";
rb->write( out, error, rb->strlen( error ) );
}
else
{
char string[MD5_STRING_LENGTH+1];
while( *filename == ' ' )
filename++;
rb->write( out, filename, rb->strlen( filename ) );
rb->write( out, ": ", 2 );
if( hash( string, filename ) )
rb->write( out, "FAILED open or read", 19 );
else if( rb->strncasecmp( line, string, MD5_STRING_LENGTH ) )
rb->write( out, "FAILED", 6 );
else
rb->write( out, "OK", 2 );
}
rb->write( out, "\n", 1 );
}
}
rb->close( list );
}
/*
* Return the last name from a pathname (ignoring a trailing slash if
* it exists). The returned pointer points to a statically allocated
* buffer.
*/
static char *get_basename(const char *path) {
static char temp[MAX_PATH];
char *p;
int len, isdir = 0;
rb->strcpy(temp, path);
len = rb->strlen(temp);
if (temp[len - 1] == '/')
{
/* strip trailing slash, and update length accordingly */
temp[--len] = '\0';
isdir = 1;
}
/* find the last slash, if there is one */
p = rb->strrchr(temp, '/');
/*
* re-append trailing slash if we previously removed it (the
* original NUL is still present)
*/
if(isdir)
temp[len++] = '/';
return p ? (p + 1) : temp;
}
enum plugin_status plugin_start(const void* parameter)
{
const char *arg = (const char *)parameter; /* input file path, if any */
char *basename;
int out = -1; /* output file descriptor */
char filename[MAX_PATH]; /* output file name */
void (*action)( int, const char * ) = NULL;
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
rb->cpu_boost( true );
#endif
if( arg && *arg )
{
const char *ext = rb->strrchr( arg, '.' );
DIR *dir;
rb->snprintf( filename, MAX_PATH, "%s.md5sum", arg );
if( ext )
{
if( !rb->strcmp( ext, ".md5" ) || !rb->strcmp( ext, ".md5sum" ) )
{
rb->snprintf( filename + ( ext - arg ),
MAX_PATH + rb->strlen( ext ) - rb->strlen( arg ),
".md5check" );
/* Lets check the sums */
action = hash_check;
}
else if( !rb->strcmp( ext, ".md5list" ) ) /* ugly */
{
/* Hash listed files */
action = hash_list;
}
}
if( !action )
{
dir = rb->opendir( arg );
if( dir )
{
rb->closedir( dir );
/* Hash the directory's content recursively */
action = hash_dir;
}
else
{
/* Hash the file */
action = hash_file;
}
}
}
else
{
rb->snprintf( filename, MAX_PATH, "/everything.md5sum" );
/* Hash the whole filesystem */
action = hash_dir;
arg = "/";
}
basename = get_basename(arg);
rb->lcd_putsf( 0, 1, "Hashing %s", basename );
rb->lcd_puts( 0, 2, rb->str(LANG_ACTION_STD_CANCEL) );
rb->lcd_puts( 0, 3, "Output file:" );
rb->lcd_puts( 0, 4, filename );
rb->lcd_update();
count = 0;
done = 0;
action( out, arg );
out = rb->open( filename, O_WRONLY|O_CREAT|O_TRUNC , 0666);
if( out < 0 ) return PLUGIN_ERROR;
action( out, arg );
rb->close( out );
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
rb->cpu_boost( false );
#endif
return PLUGIN_OK;
}