00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <glib.h>
00018 #include <string.h>
00019 #include <stdio.h>
00020 #include <stdlib.h>
00021 #include <unistd.h>
00022 #include <sys/time.h>
00023 #include <errno.h>
00024
00025 #include "xmmsc/xmmsc_idnumbers.h"
00026 #include "xmmsc/xmmsc_ipc_transport.h"
00027 #include "xmmsc/xmmsc_ipc_msg.h"
00028
00029 #include "xmms/xmms_log.h"
00030
00031 #include "xmms/xmms_bindata.h"
00032
00033 #include "xmmspriv/xmms_ringbuf.h"
00034 #include "xmmspriv/xmms_ipc.h"
00035 #include "xmmspriv/xmms_playlist.h"
00036 #include "xmmspriv/xmms_config.h"
00037 #include "xmmspriv/xmms_bindata.h"
00038 #include "xmmspriv/xmms_utils.h"
00039
00040 struct xmms_bindata_St {
00041 xmms_object_t obj;
00042 const gchar *bindir;
00043 };
00044
00045 static xmms_bindata_t *global_bindata;
00046
00047 static void xmms_bindata_destroy (xmms_object_t *obj);
00048
00049 typedef unsigned char md5_byte_t;
00050 typedef unsigned int md5_word_t;
00051
00052
00053 typedef struct md5_state_s {
00054 md5_word_t count[2];
00055 md5_word_t abcd[4];
00056 md5_byte_t buf[64];
00057 } md5_state_t;
00058
00059
00060 static void md5_init (md5_state_t *pms);
00061 static void md5_append (md5_state_t *pms, const md5_byte_t *data, int nbytes);
00062 static void md5_finish (md5_state_t *pms, md5_byte_t digest[16]);
00063
00064 static gchar *xmms_bindata_build_path (xmms_bindata_t *bindata, const gchar *hash);
00065
00066 static gchar *xmms_bindata_client_add (xmms_bindata_t *bindata, GString *data, xmms_error_t *err);
00067 static xmmsv_t *xmms_bindata_client_retrieve (xmms_bindata_t *bindata, const gchar *hash, xmms_error_t *err);
00068 static void xmms_bindata_client_remove (xmms_bindata_t *bindata, const gchar *hash, xmms_error_t *);
00069 static GList *xmms_bindata_client_list (xmms_bindata_t *bindata, xmms_error_t *err);
00070 static gboolean _xmms_bindata_add (xmms_bindata_t *bindata, const guchar *data, gsize len, gchar hash[33], xmms_error_t *err);
00071
00072 #include "bindata_ipc.c"
00073
00074 xmms_bindata_t *
00075 xmms_bindata_init ()
00076 {
00077 gchar *tmp;
00078 xmms_bindata_t *obj;
00079 xmms_config_property_t *cv;
00080
00081 obj = xmms_object_new (xmms_bindata_t, xmms_bindata_destroy);
00082
00083 xmms_bindata_register_ipc_commands (XMMS_OBJECT (obj));
00084
00085 tmp = XMMS_BUILD_PATH ("bindata");
00086 cv = xmms_config_property_register ("bindata.path", tmp, NULL, NULL);
00087 g_free (tmp);
00088
00089 obj->bindir = xmms_config_property_get_string (cv);
00090
00091 if (!g_file_test (obj->bindir, G_FILE_TEST_IS_DIR)) {
00092 if (g_mkdir_with_parents (obj->bindir, 0755) == -1) {
00093 xmms_log_error ("Couldn't create bindir %s", obj->bindir);
00094 }
00095 }
00096
00097 global_bindata = obj;
00098
00099 return obj;
00100 }
00101
00102 static void
00103 xmms_bindata_destroy (xmms_object_t *obj)
00104 {
00105 xmms_bindata_unregister_ipc_commands ();
00106 }
00107
00108 gchar *
00109 xmms_bindata_calculate_md5 (const guchar *data, gsize size, gchar ret[33])
00110 {
00111 md5_state_t state;
00112 md5_byte_t digest[16];
00113 int di;
00114 static gchar hex[] = {
00115 '0', '1', '2', '3', '4', '5', '6', '7',
00116 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
00117 };
00118
00119 md5_init (&state);
00120 md5_append (&state, (const md5_byte_t *)data, size);
00121 md5_finish (&state, digest);
00122
00123 for (di = 0; di < 16; ++di) {
00124 ret[di * 2] = hex[digest[di] >> 4];
00125 ret[di * 2 + 1] = hex[digest[di] & 0x0f];
00126 }
00127 ret[32] = 0;
00128 return ret;
00129 }
00130
00131 static gchar *
00132 xmms_bindata_build_path (xmms_bindata_t *bindata, const gchar *hash)
00133 {
00134 return g_build_path (G_DIR_SEPARATOR_S, bindata->bindir, hash, NULL);
00135 }
00136
00137
00138 gboolean
00139 xmms_bindata_plugin_add (const guchar *data, gsize size, gchar hash[33])
00140 {
00141 xmms_error_t err;
00142 return _xmms_bindata_add (global_bindata, data, size, hash, &err);
00143 }
00144
00145 static gboolean
00146 _xmms_bindata_add (xmms_bindata_t *bindata, const guchar *data, gsize len, gchar hash[33], xmms_error_t *err)
00147 {
00148 const guchar *ptr;
00149 gsize left;
00150 gchar *path;
00151 FILE *fp;
00152
00153 xmms_bindata_calculate_md5 (data, len, hash);
00154
00155 path = xmms_bindata_build_path (bindata, hash);
00156
00157 if (g_file_test (path, G_FILE_TEST_IS_REGULAR)) {
00158 XMMS_DBG ("file %s is already in bindata dir", hash);
00159 g_free (path);
00160 return TRUE;
00161 }
00162
00163 XMMS_DBG ("Creating %s", path);
00164 fp = fopen (path, "wb");
00165 if (!fp) {
00166 xmms_log_error ("Couldn't create %s", path);
00167 xmms_error_set (err, XMMS_ERROR_GENERIC, "Couldn't create file on server!");
00168 g_free (path);
00169 return FALSE;
00170 }
00171
00172
00173 ptr = data;
00174 left = len;
00175
00176 while (left > 0) {
00177 size_t w;
00178
00179 w = fwrite (ptr, 1, left, fp);
00180 if (!w && ferror (fp)) {
00181 fclose (fp);
00182 unlink (path);
00183
00184 xmms_log_error ("Couldn't write data");
00185 xmms_error_set (err, XMMS_ERROR_GENERIC,
00186 "Couldn't write data!");
00187 g_free (path);
00188 return FALSE;
00189 }
00190
00191 left -= w;
00192 ptr += w;
00193 }
00194
00195 fclose (fp);
00196 g_free (path);
00197
00198 return TRUE;
00199 }
00200
00201 char *
00202 xmms_bindata_client_add (xmms_bindata_t *bindata, GString *data, xmms_error_t *err)
00203 {
00204 gchar hash[33];
00205 if (_xmms_bindata_add (bindata, (guchar *)data->str, data->len, hash, err))
00206 return g_strdup (hash);
00207 return NULL;
00208 }
00209
00210 static xmmsv_t *
00211 xmms_bindata_client_retrieve (xmms_bindata_t *bindata, const gchar *hash,
00212 xmms_error_t *err)
00213 {
00214 xmmsv_t *res;
00215 gchar *path;
00216 GString *str;
00217 FILE *fp;
00218
00219 path = xmms_bindata_build_path (bindata, hash);
00220
00221 fp = fopen (path, "rb");
00222 if (!fp) {
00223 xmms_log_error ("Requesting '%s' which is not on the server", hash);
00224 xmms_error_set (err, XMMS_ERROR_NOENT, "File not found!");
00225 g_free (path);
00226 return NULL;
00227 }
00228
00229 g_free (path);
00230
00231 str = g_string_new (NULL);
00232 while (!feof (fp)) {
00233 gchar buf[1024];
00234 gint l;
00235
00236 l = fread (buf, 1, 1024, fp);
00237 if (ferror (fp)) {
00238 g_string_free (str, TRUE);
00239 xmms_log_error ("Error reading bindata '%s'", hash);
00240 xmms_error_set (err, XMMS_ERROR_GENERIC, "Error reading file");
00241 fclose (fp);
00242 return NULL;
00243 }
00244 g_string_append_len (str, buf, l);
00245 }
00246
00247 fclose (fp);
00248
00249 res = xmmsv_new_bin ((unsigned char *)str->str, str->len);
00250
00251 g_string_free (str, TRUE);
00252
00253 return res;
00254 }
00255
00256 static void
00257 xmms_bindata_client_remove (xmms_bindata_t *bindata, const gchar *hash,
00258 xmms_error_t *err)
00259 {
00260 gchar *path;
00261 path = xmms_bindata_build_path (bindata, hash);
00262 if (unlink (path) == -1) {
00263 xmms_error_set (err, XMMS_ERROR_GENERIC, "Couldn't remove file");
00264 }
00265 g_free (path);
00266 return;
00267 }
00268
00269 static GList *
00270 xmms_bindata_client_list (xmms_bindata_t *bindata, xmms_error_t *err)
00271 {
00272 GList *entries = NULL;
00273 gchar *path;
00274 const gchar *file;
00275 GDir *dir;
00276
00277 path = xmms_bindata_build_path (bindata, NULL);
00278 dir = g_dir_open (path, 0, NULL);
00279 g_free (path);
00280
00281 if (!dir) {
00282 xmms_error_set (err, XMMS_ERROR_GENERIC,
00283 "Couldn't open bindata directory");
00284 return NULL;
00285 }
00286
00287 while ((file = g_dir_read_name (dir))) {
00288 entries = g_list_prepend (entries, xmmsv_new_string (file));
00289 }
00290
00291 g_dir_close (dir);
00292
00293 return entries;
00294 }
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359 #undef BYTE_ORDER
00360 #ifdef ARCH_IS_BIG_ENDIAN
00361 # define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
00362 #else
00363 # define BYTE_ORDER 0
00364 #endif
00365
00366 #define T_MASK ((md5_word_t)~0)
00367 #define T1 (T_MASK ^ 0x28955b87)
00368 #define T2 (T_MASK ^ 0x173848a9)
00369 #define T3 0x242070db
00370 #define T4 (T_MASK ^ 0x3e423111)
00371 #define T5 (T_MASK ^ 0x0a83f050)
00372 #define T6 0x4787c62a
00373 #define T7 (T_MASK ^ 0x57cfb9ec)
00374 #define T8 (T_MASK ^ 0x02b96afe)
00375 #define T9 0x698098d8
00376 #define T10 (T_MASK ^ 0x74bb0850)
00377 #define T11 (T_MASK ^ 0x0000a44e)
00378 #define T12 (T_MASK ^ 0x76a32841)
00379 #define T13 0x6b901122
00380 #define T14 (T_MASK ^ 0x02678e6c)
00381 #define T15 (T_MASK ^ 0x5986bc71)
00382 #define T16 0x49b40821
00383 #define T17 (T_MASK ^ 0x09e1da9d)
00384 #define T18 (T_MASK ^ 0x3fbf4cbf)
00385 #define T19 0x265e5a51
00386 #define T20 (T_MASK ^ 0x16493855)
00387 #define T21 (T_MASK ^ 0x29d0efa2)
00388 #define T22 0x02441453
00389 #define T23 (T_MASK ^ 0x275e197e)
00390 #define T24 (T_MASK ^ 0x182c0437)
00391 #define T25 0x21e1cde6
00392 #define T26 (T_MASK ^ 0x3cc8f829)
00393 #define T27 (T_MASK ^ 0x0b2af278)
00394 #define T28 0x455a14ed
00395 #define T29 (T_MASK ^ 0x561c16fa)
00396 #define T30 (T_MASK ^ 0x03105c07)
00397 #define T31 0x676f02d9
00398 #define T32 (T_MASK ^ 0x72d5b375)
00399 #define T33 (T_MASK ^ 0x0005c6bd)
00400 #define T34 (T_MASK ^ 0x788e097e)
00401 #define T35 0x6d9d6122
00402 #define T36 (T_MASK ^ 0x021ac7f3)
00403 #define T37 (T_MASK ^ 0x5b4115bb)
00404 #define T38 0x4bdecfa9
00405 #define T39 (T_MASK ^ 0x0944b49f)
00406 #define T40 (T_MASK ^ 0x4140438f)
00407 #define T41 0x289b7ec6
00408 #define T42 (T_MASK ^ 0x155ed805)
00409 #define T43 (T_MASK ^ 0x2b10cf7a)
00410 #define T44 0x04881d05
00411 #define T45 (T_MASK ^ 0x262b2fc6)
00412 #define T46 (T_MASK ^ 0x1924661a)
00413 #define T47 0x1fa27cf8
00414 #define T48 (T_MASK ^ 0x3b53a99a)
00415 #define T49 (T_MASK ^ 0x0bd6ddbb)
00416 #define T50 0x432aff97
00417 #define T51 (T_MASK ^ 0x546bdc58)
00418 #define T52 (T_MASK ^ 0x036c5fc6)
00419 #define T53 0x655b59c3
00420 #define T54 (T_MASK ^ 0x70f3336d)
00421 #define T55 (T_MASK ^ 0x00100b82)
00422 #define T56 (T_MASK ^ 0x7a7ba22e)
00423 #define T57 0x6fa87e4f
00424 #define T58 (T_MASK ^ 0x01d3191f)
00425 #define T59 (T_MASK ^ 0x5cfebceb)
00426 #define T60 0x4e0811a1
00427 #define T61 (T_MASK ^ 0x08ac817d)
00428 #define T62 (T_MASK ^ 0x42c50dca)
00429 #define T63 0x2ad7d2bb
00430 #define T64 (T_MASK ^ 0x14792c6e)
00431
00432
00433 static void
00434 md5_process (md5_state_t *pms, const md5_byte_t *data )
00435 {
00436 md5_word_t
00437 a = pms->abcd[0], b = pms->abcd[1],
00438 c = pms->abcd[2], d = pms->abcd[3];
00439 md5_word_t t;
00440 #if BYTE_ORDER > 0
00441
00442 md5_word_t X[16];
00443 #else
00444
00445 md5_word_t xbuf[16];
00446 const md5_word_t *X;
00447 #endif
00448
00449 {
00450 #if BYTE_ORDER == 0
00451
00452
00453
00454
00455
00456 static const int w = 1;
00457
00458 if (*((const md5_byte_t *)&w))
00459 #endif
00460 #if BYTE_ORDER <= 0
00461 {
00462
00463
00464
00465
00466 if (!((data - (const md5_byte_t *)0) & 3)) {
00467
00468 X = (const md5_word_t *)data;
00469 } else {
00470
00471 memcpy (xbuf, data, 64);
00472 X = xbuf;
00473 }
00474 }
00475 #endif
00476 #if BYTE_ORDER == 0
00477 else
00478 #endif
00479 #if BYTE_ORDER >= 0
00480 {
00481
00482
00483
00484
00485 const md5_byte_t *xp = data;
00486 int i;
00487
00488 # if BYTE_ORDER == 0
00489 X = xbuf;
00490 # else
00491 # define xbuf X
00492 # endif
00493 for (i = 0; i < 16; ++i, xp += 4)
00494 xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
00495 }
00496 #endif
00497 }
00498
00499 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
00500
00501
00502
00503
00504 #define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
00505 #define SET(a, b, c, d, k, s, Ti)\
00506 t = a + F (b,c,d) + X[k] + Ti;\
00507 a = ROTATE_LEFT (t, s) + b
00508
00509 SET (a, b, c, d, 0, 7, T1);
00510 SET (d, a, b, c, 1, 12, T2);
00511 SET (c, d, a, b, 2, 17, T3);
00512 SET (b, c, d, a, 3, 22, T4);
00513 SET (a, b, c, d, 4, 7, T5);
00514 SET (d, a, b, c, 5, 12, T6);
00515 SET (c, d, a, b, 6, 17, T7);
00516 SET (b, c, d, a, 7, 22, T8);
00517 SET (a, b, c, d, 8, 7, T9);
00518 SET (d, a, b, c, 9, 12, T10);
00519 SET (c, d, a, b, 10, 17, T11);
00520 SET (b, c, d, a, 11, 22, T12);
00521 SET (a, b, c, d, 12, 7, T13);
00522 SET (d, a, b, c, 13, 12, T14);
00523 SET (c, d, a, b, 14, 17, T15);
00524 SET (b, c, d, a, 15, 22, T16);
00525 #undef SET
00526
00527
00528
00529
00530 #define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
00531 #define SET(a, b, c, d, k, s, Ti)\
00532 t = a + G (b,c,d) + X[k] + Ti;\
00533 a = ROTATE_LEFT (t, s) + b
00534
00535 SET (a, b, c, d, 1, 5, T17);
00536 SET (d, a, b, c, 6, 9, T18);
00537 SET (c, d, a, b, 11, 14, T19);
00538 SET (b, c, d, a, 0, 20, T20);
00539 SET (a, b, c, d, 5, 5, T21);
00540 SET (d, a, b, c, 10, 9, T22);
00541 SET (c, d, a, b, 15, 14, T23);
00542 SET (b, c, d, a, 4, 20, T24);
00543 SET (a, b, c, d, 9, 5, T25);
00544 SET (d, a, b, c, 14, 9, T26);
00545 SET (c, d, a, b, 3, 14, T27);
00546 SET (b, c, d, a, 8, 20, T28);
00547 SET (a, b, c, d, 13, 5, T29);
00548 SET (d, a, b, c, 2, 9, T30);
00549 SET (c, d, a, b, 7, 14, T31);
00550 SET (b, c, d, a, 12, 20, T32);
00551 #undef SET
00552
00553
00554
00555
00556 #define H(x, y, z) ((x) ^ (y) ^ (z))
00557 #define SET(a, b, c, d, k, s, Ti)\
00558 t = a + H (b,c,d) + X[k] + Ti;\
00559 a = ROTATE_LEFT (t, s) + b
00560
00561 SET (a, b, c, d, 5, 4, T33);
00562 SET (d, a, b, c, 8, 11, T34);
00563 SET (c, d, a, b, 11, 16, T35);
00564 SET (b, c, d, a, 14, 23, T36);
00565 SET (a, b, c, d, 1, 4, T37);
00566 SET (d, a, b, c, 4, 11, T38);
00567 SET (c, d, a, b, 7, 16, T39);
00568 SET (b, c, d, a, 10, 23, T40);
00569 SET (a, b, c, d, 13, 4, T41);
00570 SET (d, a, b, c, 0, 11, T42);
00571 SET (c, d, a, b, 3, 16, T43);
00572 SET (b, c, d, a, 6, 23, T44);
00573 SET (a, b, c, d, 9, 4, T45);
00574 SET (d, a, b, c, 12, 11, T46);
00575 SET (c, d, a, b, 15, 16, T47);
00576 SET (b, c, d, a, 2, 23, T48);
00577 #undef SET
00578
00579
00580
00581
00582 #define I(x, y, z) ((y) ^ ((x) | ~(z)))
00583 #define SET(a, b, c, d, k, s, Ti)\
00584 t = a + I (b,c,d) + X[k] + Ti;\
00585 a = ROTATE_LEFT (t, s) + b
00586
00587 SET (a, b, c, d, 0, 6, T49);
00588 SET (d, a, b, c, 7, 10, T50);
00589 SET (c, d, a, b, 14, 15, T51);
00590 SET (b, c, d, a, 5, 21, T52);
00591 SET (a, b, c, d, 12, 6, T53);
00592 SET (d, a, b, c, 3, 10, T54);
00593 SET (c, d, a, b, 10, 15, T55);
00594 SET (b, c, d, a, 1, 21, T56);
00595 SET (a, b, c, d, 8, 6, T57);
00596 SET (d, a, b, c, 15, 10, T58);
00597 SET (c, d, a, b, 6, 15, T59);
00598 SET (b, c, d, a, 13, 21, T60);
00599 SET (a, b, c, d, 4, 6, T61);
00600 SET (d, a, b, c, 11, 10, T62);
00601 SET (c, d, a, b, 2, 15, T63);
00602 SET (b, c, d, a, 9, 21, T64);
00603 #undef SET
00604
00605
00606
00607
00608 pms->abcd[0] += a;
00609 pms->abcd[1] += b;
00610 pms->abcd[2] += c;
00611 pms->abcd[3] += d;
00612 }
00613
00614 static void
00615 md5_init (md5_state_t *pms)
00616 {
00617 pms->count[0] = pms->count[1] = 0;
00618 pms->abcd[0] = 0x67452301;
00619 pms->abcd[1] = T_MASK ^ 0x10325476;
00620 pms->abcd[2] = T_MASK ^ 0x67452301;
00621 pms->abcd[3] = 0x10325476;
00622 }
00623
00624 static void
00625 md5_append (md5_state_t *pms, const md5_byte_t *data, int nbytes)
00626 {
00627 const md5_byte_t *p = data;
00628 int left = nbytes;
00629 int offset = (pms->count[0] >> 3) & 63;
00630 md5_word_t nbits = (md5_word_t)(nbytes << 3);
00631
00632 if (nbytes <= 0)
00633 return;
00634
00635
00636 pms->count[1] += nbytes >> 29;
00637 pms->count[0] += nbits;
00638 if (pms->count[0] < nbits)
00639 pms->count[1]++;
00640
00641
00642 if (offset) {
00643 int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
00644
00645 memcpy (pms->buf + offset, p, copy);
00646 if (offset + copy < 64)
00647 return;
00648 p += copy;
00649 left -= copy;
00650 md5_process (pms, pms->buf);
00651 }
00652
00653
00654 for (; left >= 64; p += 64, left -= 64)
00655 md5_process (pms, p);
00656
00657
00658 if (left)
00659 memcpy (pms->buf, p, left);
00660 }
00661
00662 static void
00663 md5_finish (md5_state_t *pms, md5_byte_t digest[16])
00664 {
00665 static const md5_byte_t pad[64] = {
00666 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00667 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00668 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00669 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
00670 };
00671 md5_byte_t data[8];
00672 int i;
00673
00674
00675 for (i = 0; i < 8; ++i)
00676 data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
00677
00678 md5_append (pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
00679
00680 md5_append (pms, data, 8);
00681 for (i = 0; i < 16; ++i)
00682 digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
00683 }