A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 300 lines 8.1 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2008 Antoine Cellerier <dionoea -at- videolan -dot- org> 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 2 15 * of the License, or (at your option) any later version. 16 * 17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 * KIND, either express or implied. 19 * 20 ****************************************************************************/ 21 22#include "plugin.h" 23#include "lib/md5.h" 24 25 26 27#define BUFFERSIZE 16384 28 29static int count = 0; 30static int done = 0; 31static bool quit = false; 32 33static int hash( char *string, const char *path ) 34{ 35 static char buffer[BUFFERSIZE]; 36 ssize_t len; 37 struct md5_s md5; 38 int in = rb->open( path, O_RDONLY ); 39 if( in < 0 ) return -1; 40 41 InitMD5( &md5 ); 42 while( !quit && ( len = rb->read( in, buffer, sizeof(buffer) ) ) > 0 ) 43 { 44 AddMD5( &md5, buffer, len ); 45 46 if( rb->get_action(CONTEXT_STD, TIMEOUT_NOBLOCK) == ACTION_STD_CANCEL ) 47 quit = true; 48 } 49 50 EndMD5( &md5 ); 51 52 psz_md5_hash( string, &md5 ); 53 54 rb->close( in ); 55 return 0; 56} 57 58static void hash_file( int out, const char *path ) 59{ 60 if( out < 0 ) 61 count++; 62 else 63 { 64 char string[MD5_STRING_LENGTH+1]; 65 int status; 66 done++; 67 rb->splashf( 0, "%d / %d : %s", done, count, path ); 68 status = hash( string, path ); 69 70 if( quit ) 71 return; 72 73 if( status ) 74 rb->write( out, "error", 5 ); 75 else 76 rb->write( out, string, MD5_STRING_LENGTH ); 77 rb->write( out, " ", 2 ); 78 rb->write( out, path, rb->strlen( path ) ); 79 rb->write( out, "\n", 1 ); 80 81 rb->yield(); 82 } 83} 84 85static void hash_dir( int out, const char *path ) 86{ 87 DIR *dir; 88 struct dirent *entry; 89 90 dir = rb->opendir( path ); 91 if( dir ) 92 { 93 while( !quit && ( entry = rb->readdir( dir ) ) ) 94 { 95 char childpath[MAX_PATH]; 96 rb->snprintf( childpath, MAX_PATH, "%s/%s", 97 rb->strcmp( path, "/" ) ? path : "", entry->d_name ); 98 99 struct dirinfo info = rb->dir_get_info(dir, entry); 100 if (info.attribute & ATTR_DIRECTORY) 101 { 102 if( rb->strcmp( entry->d_name, "." ) 103 && rb->strcmp( entry->d_name, ".." ) ) 104 { 105 /* Got a sub directory */ 106 hash_dir( out, childpath ); 107 } 108 } 109 else 110 { 111 /* Got a file */ 112 hash_file( out, childpath ); 113 } 114 } 115 rb->closedir( dir ); 116 } 117} 118 119static void hash_list( int out, const char *path ) 120{ 121 int list = rb->open( path, O_RDONLY ); 122 char newpath[MAX_PATH]; 123 if( list < 0 ) return; 124 125 while( !quit && rb->read_line( list, newpath, MAX_PATH ) > 0 ) 126 { 127 DIR *dir = rb->opendir( newpath ); 128 if( dir ) 129 { 130 rb->closedir( dir ); 131 hash_dir( out, newpath ); 132 } 133 else 134 { 135 hash_file( out, newpath ); 136 } 137 } 138 139 rb->close( list ); 140} 141 142static void hash_check( int out, const char *path ) 143{ 144 int list = rb->open( path, O_RDONLY ); 145 char line[MD5_STRING_LENGTH+1+MAX_PATH+1]; 146 int len; 147 if( list < 0 ) return; 148 149 while( !quit && ( len = rb->read_line( list, line, MD5_STRING_LENGTH+1+MAX_PATH+1 ) ) > 0 ) 150 { 151 if( out < 0 ) 152 count++; 153 else 154 { 155 const char *filename = rb->strchr( line, ' ' ); 156 done++; 157 rb->splashf( 0, "%d / %d : %s", done, count, filename ); 158 if( !filename || len < MD5_STRING_LENGTH + 2 ) 159 { 160 const char error[] = "Malformed input line ... skipping"; 161 rb->write( out, error, rb->strlen( error ) ); 162 } 163 else 164 { 165 char string[MD5_STRING_LENGTH+1]; 166 while( *filename == ' ' ) 167 filename++; 168 rb->write( out, filename, rb->strlen( filename ) ); 169 rb->write( out, ": ", 2 ); 170 if( hash( string, filename ) ) 171 rb->write( out, "FAILED open or read", 19 ); 172 else if( rb->strncasecmp( line, string, MD5_STRING_LENGTH ) ) 173 rb->write( out, "FAILED", 6 ); 174 else 175 rb->write( out, "OK", 2 ); 176 } 177 rb->write( out, "\n", 1 ); 178 } 179 } 180 181 rb->close( list ); 182} 183 184/* 185 * Return the last name from a pathname (ignoring a trailing slash if 186 * it exists). The returned pointer points to a statically allocated 187 * buffer. 188 */ 189static char *get_basename(const char *path) { 190 static char temp[MAX_PATH]; 191 char *p; 192 int len, isdir = 0; 193 194 rb->strcpy(temp, path); 195 196 len = rb->strlen(temp); 197 198 if (temp[len - 1] == '/') 199 { 200 /* strip trailing slash, and update length accordingly */ 201 temp[--len] = '\0'; 202 isdir = 1; 203 } 204 205 /* find the last slash, if there is one */ 206 p = rb->strrchr(temp, '/'); 207 208 /* 209 * re-append trailing slash if we previously removed it (the 210 * original NUL is still present) 211 */ 212 if(isdir) 213 temp[len++] = '/'; 214 215 return p ? (p + 1) : temp; 216} 217 218enum plugin_status plugin_start(const void* parameter) 219{ 220 const char *arg = (const char *)parameter; /* input file path, if any */ 221 char *basename; 222 int out = -1; /* output file descriptor */ 223 char filename[MAX_PATH]; /* output file name */ 224 225 void (*action)( int, const char * ) = NULL; 226 227#ifdef HAVE_ADJUSTABLE_CPU_FREQ 228 rb->cpu_boost( true ); 229#endif 230 231 if( arg && *arg ) 232 { 233 const char *ext = rb->strrchr( arg, '.' ); 234 DIR *dir; 235 rb->snprintf( filename, MAX_PATH, "%s.md5sum", arg ); 236 237 if( ext ) 238 { 239 if( !rb->strcmp( ext, ".md5" ) || !rb->strcmp( ext, ".md5sum" ) ) 240 { 241 rb->snprintf( filename + ( ext - arg ), 242 MAX_PATH + rb->strlen( ext ) - rb->strlen( arg ), 243 ".md5check" ); 244 /* Lets check the sums */ 245 action = hash_check; 246 } 247 else if( !rb->strcmp( ext, ".md5list" ) ) /* ugly */ 248 { 249 /* Hash listed files */ 250 action = hash_list; 251 } 252 } 253 254 if( !action ) 255 { 256 dir = rb->opendir( arg ); 257 if( dir ) 258 { 259 rb->closedir( dir ); 260 261 /* Hash the directory's content recursively */ 262 action = hash_dir; 263 } 264 else 265 { 266 /* Hash the file */ 267 action = hash_file; 268 } 269 } 270 } 271 else 272 { 273 rb->snprintf( filename, MAX_PATH, "/everything.md5sum" ); 274 /* Hash the whole filesystem */ 275 action = hash_dir; 276 arg = "/"; 277 } 278 279 basename = get_basename(arg); 280 281 rb->lcd_putsf( 0, 1, "Hashing %s", basename ); 282 rb->lcd_puts( 0, 2, rb->str(LANG_ACTION_STD_CANCEL) ); 283 284 rb->lcd_puts( 0, 3, "Output file:" ); 285 rb->lcd_puts( 0, 4, filename ); 286 287 rb->lcd_update(); 288 count = 0; 289 done = 0; 290 action( out, arg ); 291 292 out = rb->open( filename, O_WRONLY|O_CREAT|O_TRUNC , 0666); 293 if( out < 0 ) return PLUGIN_ERROR; 294 action( out, arg ); 295 rb->close( out ); 296#ifdef HAVE_ADJUSTABLE_CPU_FREQ 297 rb->cpu_boost( false ); 298#endif 299 return PLUGIN_OK; 300}