tracker-0.16.2/src/libtracker-data/tracker-db-journal.c

Location Tool Test ID Function Issue
tracker-db-journal.c:176:3 gcc pointer-sign journal_read_uint32 pointer targets in passing argument 1 of 'read_uint32' differ in signedness
tracker-db-journal.c:1686:4 gcc pointer-sign db_journal_reader_next pointer targets in passing argument 1 of 'read_uint32' differ in signedness
tracker-db-journal.c:1883:4 gcc pointer-sign tracker_db_journal_reader_verify_last pointer targets in passing argument 1 of 'read_uint32' differ in signedness
   1 /*
   2  * Copyright (C) 2009, Nokia <ivan.frade@nokia.com>
   3  *
   4  * This library is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU Lesser General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2.1 of the License, or (at your option) any later version.
   8  *
   9  * This library is distributed in the hope that it will be useful,
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12  * Lesser General Public License for more details.
  13  *
  14  * You should have received a copy of the GNU Lesser General Public
  15  * License along with this library; if not, write to the
  16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  17  * Boston, MA  02110-1301, USA.
  18  *
  19  * Author: Philip Van Hoof <philip@codeminded.be>
  20  */
  21 
  22 #include "config.h"
  23 
  24 #define _GNU_SOURCE
  25 
  26 #include <unistd.h>
  27 #include <sys/types.h>
  28 #include <stdio.h>
  29 #include <string.h>
  30 #include <sys/stat.h>
  31 #include <unistd.h>
  32 #include <errno.h>
  33 #include <fcntl.h>
  34 #include <stdlib.h>
  35 
  36 #include <glib/gstdio.h>
  37 
  38 #ifndef O_LARGEFILE
  39 # define O_LARGEFILE 0
  40 #endif
  41 
  42 #include <libtracker-common/tracker-crc32.h>
  43 
  44 #include "tracker-db-journal.h"
  45 
  46 #ifndef DISABLE_JOURNAL
  47 
  48 #define MIN_BLOCK_SIZE    1024
  49 
  50 /*
  51  * data_format:
  52  * #... 0000 0000 (total size is 4 bytes)
  53  *         | |||`- resource insert (all other bits must be 0 if 1)
  54  *         | ||`-- object type (1 = id, 0 = cstring)
  55  *         | |`--- operation type (0 = insert, 1 = delete)
  56  *         | `---- graph (0 = default graph, 1 = named graph)
  57  *         `------ update (0 = insert, 1 = update)
  58  */
  59 
  60 typedef enum {
  61 	DATA_FORMAT_RESOURCE_INSERT  = 1 << 0,
  62 	DATA_FORMAT_OBJECT_ID        = 1 << 1,
  63 	DATA_FORMAT_OPERATION_DELETE = 1 << 2,
  64 	DATA_FORMAT_GRAPH            = 1 << 3,
  65 	DATA_FORMAT_OPERATION_UPDATE = 1 << 4
  66 } DataFormat;
  67 
  68 typedef enum {
  69 	TRANSACTION_FORMAT_NONE      = 0,
  70 	TRANSACTION_FORMAT_DATA      = 1 << 0,
  71 	TRANSACTION_FORMAT_ONTOLOGY  = 1 << 1,
  72 } TransactionFormat;
  73 
  74 typedef struct {
  75 	gchar *filename;
  76 	GDataInputStream *stream;
  77 	GInputStream *underlying_stream;
  78 	GFileInfo *underlying_stream_info;
  79 	GMappedFile *file;
  80 	const gchar *current;
  81 	const gchar *end;
  82 	const gchar *entry_begin;
  83 	const gchar *entry_end;
  84 	const gchar *last_success;
  85 	const gchar *start;
  86 	guint32 amount_of_triples;
  87 	gint64 time;
  88 	TrackerDBJournalEntryType type;
  89 	gchar *uri;
  90 	gint g_id;
  91 	gint s_id;
  92 	gint p_id;
  93 	gint o_id;
  94 	gchar *object;
  95 	guint current_file;
  96 	gchar *rotate_to;
  97 } JournalReader;
  98 
  99 typedef struct {
 100 	gchar *journal_filename;
 101 	int journal;
 102 	gsize cur_size;
 103 	guint cur_block_len;
 104 	guint cur_block_alloc;
 105 	gchar *cur_block;
 106 	guint cur_entry_amount;
 107 	guint cur_pos;
 108 } JournalWriter;
 109 
 110 static struct {
 111 	gsize chunk_size;
 112 	gboolean do_rotating;
 113 	gchar *rotate_to;
 114 	gboolean rotate_progress_flag;
 115 } rotating_settings = {0};
 116 
 117 static JournalReader reader = {0};
 118 static JournalWriter writer = {0};
 119 static JournalWriter ontology_writer = {0};
 120 
 121 static TransactionFormat current_transaction_format;
 122 
 123 #if GLIB_CHECK_VERSION (2, 24, 2)
 124 static gboolean tracker_db_journal_rotate (GError **error);
 125 #endif /* GLib check */
 126 
 127 static gboolean
 128 journal_eof (JournalReader *jreader)
 129 {
 130 	if (jreader->stream) {
 131 		GBufferedInputStream *bstream;
 132 
 133 		bstream = G_BUFFERED_INPUT_STREAM (jreader->stream);
 134 
 135 		if (g_buffered_input_stream_get_available (bstream) == 0) {
 136 			if (g_buffered_input_stream_fill (bstream, -1, NULL, NULL) == 0) {
 137 				return TRUE;
 138 			}
 139 		}
 140 	} else {
 141 		if (jreader->current >= jreader->end) {
 142 			return TRUE;
 143 		}
 144 	}
 145 
 146 	return FALSE;
 147 }
 148 
 149 static guint32
 150 read_uint32 (const guint8 *data)
 151 {
 152 	return data[0] << 24 |
 153 	       data[1] << 16 |
 154 	       data[2] << 8 |
 155 	       data[3];
 156 }
 157 
 158 static guint32
 159 journal_read_uint32 (JournalReader  *jreader,
 160                      GError        **error)
 161 {
 162 	guint32 result;
 163 
 164 	if (jreader->stream) {
 165 		result = g_data_input_stream_read_uint32 (jreader->stream, NULL, error);
 166 	} else {
 167 		if (jreader->end - jreader->current < sizeof (guint32)) {
 168 			/* damaged journal entry */
 169 			g_set_error (error, TRACKER_DB_JOURNAL_ERROR,
 170 			             TRACKER_DB_JOURNAL_ERROR_DAMAGED_JOURNAL_ENTRY,
 171 			             "Damaged journal entry, %d < sizeof(guint32)",
 172 			             (gint) (jreader->end - jreader->current));
 173 			return 0;
 174 		}
 175 
 176 		result = read_uint32 (jreader->current);
pointer targets in passing argument 1 of 'read_uint32' differ in signedness
(emitted by gcc)
177 jreader->current += 4; 178 } 179 180 return result; 181 } 182 183 /* based on GDataInputStream code */ 184 static gssize 185 scan_for_nul (GBufferedInputStream *stream, 186 gsize *checked_out) 187 { 188 const gchar *buffer; 189 gsize start, end, peeked; 190 gint i; 191 gsize available, checked; 192 193 checked = *checked_out; 194 195 start = checked; 196 buffer = (const gchar *) g_buffered_input_stream_peek_buffer (stream, &available) + start; 197 end = available; 198 peeked = end - start; 199 200 for (i = 0; checked < available && i < peeked; i++) { 201 if (buffer[i] == '\0') { 202 return (start + i); 203 } 204 } 205 206 checked = end; 207 208 *checked_out = checked; 209 return -1; 210 } 211 212 static gchar * 213 journal_read_string (JournalReader *jreader, 214 GError **error) 215 { 216 gchar *result; 217 218 if (jreader->stream) { 219 /* based on GDataInputStream code */ 220 221 GBufferedInputStream *bstream; 222 gsize checked; 223 gssize found_pos; 224 225 bstream = G_BUFFERED_INPUT_STREAM (jreader->stream); 226 227 checked = 0; 228 229 while ((found_pos = scan_for_nul (bstream, &checked)) == -1) { 230 if (g_buffered_input_stream_get_available (bstream) == g_buffered_input_stream_get_buffer_size (bstream)) { 231 g_buffered_input_stream_set_buffer_size (bstream, 2 * g_buffered_input_stream_get_buffer_size (bstream)); 232 } 233 234 if (g_buffered_input_stream_fill (bstream, -1, NULL, error) <= 0) { 235 /* error or end of stream */ 236 g_set_error (error, TRACKER_DB_JOURNAL_ERROR, 237 TRACKER_DB_JOURNAL_ERROR_DAMAGED_JOURNAL_ENTRY, 238 "Damaged journal entry, no terminating zero found"); 239 return NULL; 240 } 241 } 242 243 result = g_malloc (found_pos + 1); 244 g_input_stream_read (G_INPUT_STREAM (bstream), result, found_pos + 1, NULL, NULL); 245 } else { 246 gsize str_length; 247 248 str_length = strnlen (jreader->current, jreader->end - jreader->current); 249 if (str_length == jreader->end - jreader->current) { 250 /* damaged journal entry (no terminating '\0' character) */ 251 g_set_error (error, TRACKER_DB_JOURNAL_ERROR, 252 TRACKER_DB_JOURNAL_ERROR_DAMAGED_JOURNAL_ENTRY, 253 "Damaged journal entry, no terminating zero found"); 254 return NULL; 255 256 } 257 258 result = g_strdup (jreader->current); 259 260 jreader->current += str_length + 1; 261 } 262 263 if (!g_utf8_validate (result, -1, NULL)) { 264 /* damaged journal entry (invalid UTF-8) */ 265 g_set_error (error, TRACKER_DB_JOURNAL_ERROR, 266 TRACKER_DB_JOURNAL_ERROR_DAMAGED_JOURNAL_ENTRY, 267 "Damaged journal entry, invalid UTF-8"); 268 g_free (result); 269 return NULL; 270 } 271 272 return result; 273 } 274 275 static gboolean 276 journal_verify_header (JournalReader *jreader) 277 { 278 gchar header[8]; 279 gint i; 280 GError *error = NULL; 281 282 /* Version 00003 is identical, it just has no UPDATE operations */ 283 284 if (jreader->stream) { 285 for (i = 0; i < sizeof (header); i++) { 286 header[i] = g_data_input_stream_read_byte (jreader->stream, NULL, &error); 287 if (error) { 288 g_clear_error (&error); 289 return FALSE; 290 } 291 } 292 293 if (memcmp (header, "trlog\00004", 8) && memcmp (header, "trlog\00003", 8)) { 294 return FALSE; 295 } 296 } else { 297 /* verify journal file header */ 298 if (jreader->end - jreader->current < 8) { 299 return FALSE; 300 } 301 302 if (memcmp (jreader->current, "trlog\00004", 8) && memcmp (jreader->current, "trlog\00003", 8)) { 303 return FALSE; 304 } 305 306 jreader->current += 8; 307 } 308 309 return TRUE; 310 } 311 312 void 313 tracker_db_journal_get_rotating (gboolean *do_rotating, 314 gsize *chunk_size, 315 gchar **rotate_to) 316 { 317 *do_rotating = rotating_settings.do_rotating; 318 *chunk_size = rotating_settings.chunk_size; 319 if (rotating_settings.rotate_to) { 320 *rotate_to = g_strdup (rotating_settings.rotate_to); 321 } else { 322 *rotate_to = NULL; 323 } 324 } 325 326 void 327 tracker_db_journal_set_rotating (gboolean do_rotating, 328 gsize chunk_size, 329 const gchar *rotate_to) 330 { 331 rotating_settings.do_rotating = do_rotating; 332 rotating_settings.chunk_size = chunk_size; 333 g_free (rotating_settings.rotate_to); 334 if (rotate_to) { 335 rotating_settings.rotate_to = g_strdup (rotate_to); 336 } else { 337 rotating_settings.rotate_to = NULL; 338 } 339 } 340 341 static gint 342 nearest_pow (gint num) 343 { 344 gint n = 1; 345 while (n < num) 346 n <<= 1; 347 return n; 348 } 349 350 static void 351 cur_block_maybe_expand (JournalWriter *jwriter, guint len) 352 { 353 guint want_alloc = jwriter->cur_block_len + len; 354 355 if (want_alloc > jwriter->cur_block_alloc) { 356 want_alloc = nearest_pow (want_alloc); 357 want_alloc = MAX (want_alloc, MIN_BLOCK_SIZE); 358 jwriter->cur_block = g_realloc (jwriter->cur_block, want_alloc); 359 jwriter->cur_block_alloc = want_alloc; 360 } 361 } 362 363 static void 364 cur_block_kill (JournalWriter *jwriter) 365 { 366 jwriter->cur_block_len = 0; 367 jwriter->cur_pos = 0; 368 jwriter->cur_entry_amount = 0; 369 jwriter->cur_block_alloc = 0; 370 371 g_free (jwriter->cur_block); 372 jwriter->cur_block = NULL; 373 } 374 375 static void 376 cur_setnum (gchar *dest, 377 guint *pos, 378 guint32 val) 379 { 380 memset (dest + (*pos)++, val >> 24 & 0xff, 1); 381 memset (dest + (*pos)++, val >> 16 & 0xff, 1); 382 memset (dest + (*pos)++, val >> 8 & 0xff, 1); 383 memset (dest + (*pos)++, val >> 0 & 0xff, 1); 384 } 385 386 static void 387 cur_setstr (gchar *dest, 388 guint *pos, 389 const gchar *str, 390 gsize len) 391 { 392 memcpy (dest + *pos, str, len); 393 (*pos) += len; 394 memset (dest + (*pos)++, 0 & 0xff, 1); 395 } 396 397 static gboolean 398 write_all_data (int fd, 399 gchar *data, 400 gsize len, 401 GError **error) 402 { 403 gssize written; 404 405 while (len > 0) { 406 written = write (fd, data, len); 407 408 if (written < 0) { 409 gint err = errno; 410 411 if (err == EINTR) { 412 /* interrupted by signal, try again */ 413 continue; 414 } 415 416 g_set_error (error, TRACKER_DB_JOURNAL_ERROR, 417 TRACKER_DB_JOURNAL_ERROR_COULD_NOT_WRITE, 418 "Could not write to journal file, %s", 419 g_strerror (err)); 420 421 return FALSE; 422 } else if (written == 0) { 423 g_set_error (error, TRACKER_DB_JOURNAL_ERROR, 424 TRACKER_DB_JOURNAL_ERROR_COULD_NOT_WRITE, 425 "Could not write to journal file, write returned 0 without error"); 426 427 return FALSE; 428 } 429 430 len -= written; 431 data += written; 432 } 433 434 return TRUE; /* Succeeded! */ 435 } 436 437 GQuark 438 tracker_db_journal_error_quark (void) 439 { 440 return g_quark_from_static_string (TRACKER_DB_JOURNAL_ERROR_DOMAIN); 441 } 442 443 static gboolean 444 db_journal_init_file (JournalWriter *jwriter, 445 gboolean truncate, 446 GError **error) 447 { 448 struct stat st; 449 int flags; 450 int mode; 451 452 jwriter->cur_block_len = 0; 453 jwriter->cur_pos = 0; 454 jwriter->cur_entry_amount = 0; 455 jwriter->cur_block_alloc = 0; 456 jwriter->cur_block = NULL; 457 458 mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; 459 flags = O_WRONLY | O_APPEND | O_CREAT | O_LARGEFILE; 460 if (truncate) { 461 /* existing journal contents are invalid: reindex where journal 462 * does not even contain a single valid entry 463 * 464 * or should be ignored: only for test cases 465 */ 466 flags |= O_TRUNC; 467 } 468 469 jwriter->journal = g_open (jwriter->journal_filename, flags, mode); 470 471 if (jwriter->journal == -1) { 472 g_set_error (error, TRACKER_DB_JOURNAL_ERROR, 473 TRACKER_DB_JOURNAL_ERROR_COULD_NOT_WRITE, 474 "Could not open journal for writing, %s", 475 g_strerror (errno)); 476 return FALSE; 477 } 478 479 if (fstat (jwriter->journal, &st) == 0) { 480 jwriter->cur_size = (gsize) st.st_size; 481 } 482 483 if (jwriter->cur_size == 0) { 484 g_assert (jwriter->cur_block_len == 0); 485 g_assert (jwriter->cur_block_alloc == 0); 486 g_assert (jwriter->cur_block == NULL); 487 488 cur_block_maybe_expand (jwriter, 8); 489 490 jwriter->cur_block[0] = 't'; 491 jwriter->cur_block[1] = 'r'; 492 jwriter->cur_block[2] = 'l'; 493 jwriter->cur_block[3] = 'o'; 494 jwriter->cur_block[4] = 'g'; 495 jwriter->cur_block[5] = '\0'; 496 jwriter->cur_block[6] = '0'; 497 jwriter->cur_block[7] = '4'; 498 499 if (!write_all_data (jwriter->journal, jwriter->cur_block, 8, error)) { 500 cur_block_kill (jwriter); 501 /* delete empty journal file */ 502 g_unlink (jwriter->journal_filename); 503 close (jwriter->journal); 504 jwriter->journal = 0; 505 return FALSE; 506 } 507 508 jwriter->cur_size += 8; 509 cur_block_kill (jwriter); 510 } 511 512 return TRUE; 513 } 514 515 static gboolean 516 db_journal_writer_init (JournalWriter *jwriter, 517 gboolean truncate, 518 gboolean global_writer, 519 const gchar *filename, 520 GError **error) 521 { 522 gchar *directory; 523 gint mode; 524 GError *n_error = NULL; 525 gboolean ret; 526 527 directory = g_path_get_dirname (filename); 528 if (g_strcmp0 (directory, ".")) { 529 mode = S_IRWXU | S_IRWXG | S_IRWXO; 530 if (g_mkdir_with_parents (directory, mode)) { 531 532 g_set_error (error, TRACKER_DB_JOURNAL_ERROR, 533 TRACKER_DB_JOURNAL_ERROR_COULD_NOT_WRITE, 534 "tracker data directory does not exist and " 535 "could not be created: %s", 536 g_strerror (errno)); 537 g_free (directory); 538 539 return FALSE; 540 } 541 } 542 g_free (directory); 543 544 jwriter->journal_filename = g_strdup (filename); 545 546 ret = db_journal_init_file (jwriter, truncate, &n_error); 547 548 if (n_error) { 549 g_propagate_error (error, n_error); 550 g_free (jwriter->journal_filename); 551 jwriter->journal_filename = NULL; 552 } 553 554 return ret; 555 } 556 557 gboolean 558 tracker_db_journal_init (const gchar *filename, 559 gboolean truncate, 560 GError **error) 561 { 562 gboolean ret; 563 const gchar *filename_use; 564 gchar *filename_free = NULL; 565 GError *n_error = NULL; 566 567 g_return_val_if_fail (writer.journal == 0, FALSE); 568 569 if (filename == NULL) { 570 /* Used mostly for testing */ 571 filename_use = g_build_filename (g_get_user_data_dir (), 572 "tracker", 573 "data", 574 TRACKER_DB_JOURNAL_FILENAME, 575 NULL); 576 filename_free = (gchar *) filename_use; 577 } else { 578 filename_use = filename; 579 } 580 581 ret = db_journal_writer_init (&writer, truncate, TRUE, filename_use, &n_error); 582 583 if (n_error) { 584 g_propagate_error (error, n_error); 585 } 586 587 g_free (filename_free); 588 589 return ret; 590 } 591 592 static gboolean 593 db_journal_ontology_init (GError **error) 594 { 595 gboolean ret; 596 gchar *filename; 597 GError *n_error = NULL; 598 599 g_return_val_if_fail (ontology_writer.journal == 0, FALSE); 600 601 filename = g_build_filename (g_get_user_data_dir (), 602 "tracker", 603 "data", 604 TRACKER_DB_JOURNAL_ONTOLOGY_FILENAME, 605 NULL); 606 607 ret = db_journal_writer_init (&ontology_writer, FALSE, FALSE, filename, &n_error); 608 609 if (n_error) { 610 g_propagate_error (error, n_error); 611 } 612 613 g_free (filename); 614 615 return ret; 616 } 617 618 static gboolean 619 db_journal_writer_shutdown (JournalWriter *jwriter, 620 GError **error) 621 { 622 g_free (jwriter->journal_filename); 623 jwriter->journal_filename = NULL; 624 625 if (jwriter->journal == 0) { 626 return TRUE; 627 } 628 629 if (close (jwriter->journal) != 0) { 630 g_set_error (error, TRACKER_DB_JOURNAL_ERROR, 631 TRACKER_DB_JOURNAL_ERROR_COULD_NOT_CLOSE, 632 "Could not close journal, %s", 633 g_strerror (errno)); 634 return FALSE; 635 } 636 637 jwriter->journal = 0; 638 639 return TRUE; 640 } 641 642 gboolean 643 tracker_db_journal_shutdown (GError **error) 644 { 645 GError *n_error = NULL; 646 gboolean ret; 647 648 ret = db_journal_writer_shutdown (&writer, &n_error); 649 650 if (n_error) { 651 g_propagate_error (error, n_error); 652 } 653 654 return ret; 655 } 656 657 gsize 658 tracker_db_journal_get_size (void) 659 { 660 g_return_val_if_fail (writer.journal > 0, FALSE); 661 662 return writer.cur_size; 663 } 664 665 const gchar * 666 tracker_db_journal_get_filename (void) 667 { 668 /* Journal doesn't have to be open to get the filename, for example when 669 * the file didn't exist and it was attempted opened in only read mode. */ 670 return (const gchar*) writer.journal_filename; 671 } 672 673 static gboolean 674 db_journal_writer_start_transaction (JournalWriter *jwriter, 675 time_t time, 676 TransactionFormat kind) 677 { 678 guint size; 679 680 g_return_val_if_fail (jwriter->journal > 0, FALSE); 681 g_return_val_if_fail (current_transaction_format == TRANSACTION_FORMAT_NONE, FALSE); 682 683 current_transaction_format = kind; 684 685 size = sizeof (guint32) * 3; 686 cur_block_maybe_expand (jwriter, size); 687 688 /* Leave space for size, amount and crc 689 * Check and keep in sync the offset variable at 690 * tracker_db_journal_commit_db_transaction too */ 691 692 memset (jwriter->cur_block, 0, size); 693 694 jwriter->cur_pos = jwriter->cur_block_len = size; 695 jwriter->cur_entry_amount = 0; 696 697 /* add timestamp */ 698 cur_block_maybe_expand (jwriter, sizeof (gint32)); 699 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), time); 700 jwriter->cur_block_len += sizeof (gint32); 701 702 /* Add format */ 703 cur_block_maybe_expand (jwriter, sizeof (gint32)); 704 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), kind); 705 jwriter->cur_block_len += sizeof (gint32); 706 707 return TRUE; 708 } 709 710 gboolean 711 tracker_db_journal_start_transaction (time_t time) 712 { 713 return db_journal_writer_start_transaction (&writer, time, 714 TRANSACTION_FORMAT_DATA); 715 } 716 717 gboolean 718 tracker_db_journal_start_ontology_transaction (time_t time, 719 GError **error) 720 { 721 GError *n_error = NULL; 722 723 if (!db_journal_ontology_init (&n_error)) { 724 725 if (n_error) { 726 g_propagate_error (error, n_error); 727 } 728 729 return FALSE; 730 } 731 732 return db_journal_writer_start_transaction (&ontology_writer, time, 733 TRANSACTION_FORMAT_ONTOLOGY); 734 } 735 736 static gboolean 737 db_journal_writer_append_delete_statement (JournalWriter *jwriter, 738 gint g_id, 739 gint s_id, 740 gint p_id, 741 const gchar *object) 742 { 743 gint o_len; 744 DataFormat df; 745 gint size; 746 747 g_return_val_if_fail (jwriter->journal > 0, FALSE); 748 g_return_val_if_fail (g_id >= 0, FALSE); 749 g_return_val_if_fail (s_id > 0, FALSE); 750 g_return_val_if_fail (p_id > 0, FALSE); 751 g_return_val_if_fail (object != NULL, FALSE); 752 753 o_len = strlen (object); 754 if (g_id == 0) { 755 df = DATA_FORMAT_OPERATION_DELETE; 756 size = (sizeof (guint32) * 3) + o_len + 1; 757 } else { 758 df = DATA_FORMAT_OPERATION_DELETE | DATA_FORMAT_GRAPH; 759 size = (sizeof (guint32) * 4) + o_len + 1; 760 } 761 762 cur_block_maybe_expand (jwriter, size); 763 764 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), df); 765 if (g_id > 0) { 766 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), g_id); 767 } 768 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), s_id); 769 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), p_id); 770 cur_setstr (jwriter->cur_block, &(jwriter->cur_pos), object, o_len); 771 772 jwriter->cur_entry_amount++; 773 jwriter->cur_block_len += size; 774 775 return TRUE; 776 } 777 778 gboolean 779 tracker_db_journal_append_delete_statement (gint g_id, 780 gint s_id, 781 gint p_id, 782 const gchar *object) 783 { 784 if (current_transaction_format == TRANSACTION_FORMAT_ONTOLOGY) { 785 return TRUE; 786 } 787 788 return db_journal_writer_append_delete_statement (&writer, 789 g_id, s_id, p_id, object); 790 } 791 792 static gboolean 793 db_journal_writer_append_delete_statement_id (JournalWriter *jwriter, 794 gint g_id, 795 gint s_id, 796 gint p_id, 797 gint o_id) 798 { 799 DataFormat df; 800 gint size; 801 802 g_return_val_if_fail (jwriter->journal > 0, FALSE); 803 g_return_val_if_fail (g_id >= 0, FALSE); 804 g_return_val_if_fail (s_id > 0, FALSE); 805 g_return_val_if_fail (p_id > 0, FALSE); 806 g_return_val_if_fail (o_id > 0, FALSE); 807 808 if (g_id == 0) { 809 df = DATA_FORMAT_OPERATION_DELETE | DATA_FORMAT_OBJECT_ID; 810 size = sizeof (guint32) * 4; 811 } else { 812 df = DATA_FORMAT_OPERATION_DELETE | DATA_FORMAT_OBJECT_ID | DATA_FORMAT_GRAPH; 813 size = sizeof (guint32) * 5; 814 } 815 816 cur_block_maybe_expand (jwriter, size); 817 818 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), df); 819 if (g_id > 0) { 820 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), g_id); 821 } 822 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), s_id); 823 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), p_id); 824 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), o_id); 825 826 jwriter->cur_entry_amount++; 827 jwriter->cur_block_len += size; 828 829 return TRUE; 830 } 831 832 gboolean 833 tracker_db_journal_append_delete_statement_id (gint g_id, 834 gint s_id, 835 gint p_id, 836 gint o_id) 837 { 838 if (current_transaction_format == TRANSACTION_FORMAT_ONTOLOGY) { 839 return TRUE; 840 } 841 842 return db_journal_writer_append_delete_statement_id (&writer, 843 g_id, s_id, p_id, o_id); 844 } 845 846 static gboolean 847 db_journal_writer_append_insert_statement (JournalWriter *jwriter, 848 gint g_id, 849 gint s_id, 850 gint p_id, 851 const gchar *object) 852 { 853 gint o_len; 854 DataFormat df; 855 gint size; 856 857 g_return_val_if_fail (jwriter->journal > 0, FALSE); 858 g_return_val_if_fail (g_id >= 0, FALSE); 859 g_return_val_if_fail (s_id > 0, FALSE); 860 g_return_val_if_fail (p_id > 0, FALSE); 861 g_return_val_if_fail (object != NULL, FALSE); 862 863 o_len = strlen (object); 864 if (g_id == 0) { 865 df = 0x00; 866 size = (sizeof (guint32) * 3) + o_len + 1; 867 } else { 868 df = DATA_FORMAT_GRAPH; 869 size = (sizeof (guint32) * 4) + o_len + 1; 870 } 871 872 cur_block_maybe_expand (jwriter, size); 873 874 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), df); 875 if (g_id > 0) { 876 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), g_id); 877 } 878 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), s_id); 879 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), p_id); 880 cur_setstr (jwriter->cur_block, &(jwriter->cur_pos), object, o_len); 881 882 jwriter->cur_entry_amount++; 883 jwriter->cur_block_len += size; 884 885 return TRUE; 886 } 887 888 gboolean 889 tracker_db_journal_append_insert_statement (gint g_id, 890 gint s_id, 891 gint p_id, 892 const gchar *object) 893 { 894 if (current_transaction_format == TRANSACTION_FORMAT_ONTOLOGY) { 895 return TRUE; 896 } 897 898 return db_journal_writer_append_insert_statement (&writer, 899 g_id, s_id, p_id, object); 900 } 901 902 static gboolean 903 db_journal_writer_append_insert_statement_id (JournalWriter *jwriter, 904 gint g_id, 905 gint s_id, 906 gint p_id, 907 gint o_id) 908 { 909 DataFormat df; 910 gint size; 911 912 g_return_val_if_fail (jwriter->journal > 0, FALSE); 913 g_return_val_if_fail (g_id >= 0, FALSE); 914 g_return_val_if_fail (s_id > 0, FALSE); 915 g_return_val_if_fail (p_id > 0, FALSE); 916 g_return_val_if_fail (o_id > 0, FALSE); 917 918 if (g_id == 0) { 919 df = DATA_FORMAT_OBJECT_ID; 920 size = sizeof (guint32) * 4; 921 } else { 922 df = DATA_FORMAT_OBJECT_ID | DATA_FORMAT_GRAPH; 923 size = sizeof (guint32) * 5; 924 } 925 926 cur_block_maybe_expand (jwriter, size); 927 928 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), df); 929 if (g_id > 0) { 930 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), g_id); 931 } 932 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), s_id); 933 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), p_id); 934 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), o_id); 935 936 jwriter->cur_entry_amount++; 937 jwriter->cur_block_len += size; 938 939 return TRUE; 940 } 941 942 gboolean 943 tracker_db_journal_append_insert_statement_id (gint g_id, 944 gint s_id, 945 gint p_id, 946 gint o_id) 947 { 948 if (current_transaction_format == TRANSACTION_FORMAT_ONTOLOGY) { 949 return TRUE; 950 } 951 952 return db_journal_writer_append_insert_statement_id (&writer, 953 g_id, s_id, p_id, o_id); 954 } 955 956 static gboolean 957 db_journal_writer_append_update_statement (JournalWriter *jwriter, 958 gint g_id, 959 gint s_id, 960 gint p_id, 961 const gchar *object) 962 { 963 gint o_len; 964 DataFormat df; 965 gint size; 966 967 g_return_val_if_fail (jwriter->journal > 0, FALSE); 968 g_return_val_if_fail (g_id >= 0, FALSE); 969 g_return_val_if_fail (s_id > 0, FALSE); 970 g_return_val_if_fail (p_id > 0, FALSE); 971 g_return_val_if_fail (object != NULL, FALSE); 972 973 o_len = strlen (object); 974 if (g_id == 0) { 975 df = DATA_FORMAT_OPERATION_UPDATE; 976 size = (sizeof (guint32) * 3) + o_len + 1; 977 } else { 978 df = DATA_FORMAT_OPERATION_UPDATE | DATA_FORMAT_GRAPH; 979 size = (sizeof (guint32) * 4) + o_len + 1; 980 } 981 982 cur_block_maybe_expand (jwriter, size); 983 984 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), df); 985 if (g_id > 0) { 986 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), g_id); 987 } 988 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), s_id); 989 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), p_id); 990 cur_setstr (jwriter->cur_block, &(jwriter->cur_pos), object, o_len); 991 992 jwriter->cur_entry_amount++; 993 jwriter->cur_block_len += size; 994 995 return TRUE; 996 } 997 998 gboolean 999 tracker_db_journal_append_update_statement (gint g_id, 1000 gint s_id, 1001 gint p_id, 1002 const gchar *object) 1003 { 1004 if (current_transaction_format == TRANSACTION_FORMAT_ONTOLOGY) { 1005 return TRUE; 1006 } 1007 1008 return db_journal_writer_append_update_statement (&writer, 1009 g_id, s_id, p_id, object); 1010 } 1011 1012 static gboolean 1013 db_journal_writer_append_update_statement_id (JournalWriter *jwriter, 1014 gint g_id, 1015 gint s_id, 1016 gint p_id, 1017 gint o_id) 1018 { 1019 DataFormat df; 1020 gint size; 1021 1022 g_return_val_if_fail (jwriter->journal > 0, FALSE); 1023 g_return_val_if_fail (g_id >= 0, FALSE); 1024 g_return_val_if_fail (s_id > 0, FALSE); 1025 g_return_val_if_fail (p_id > 0, FALSE); 1026 g_return_val_if_fail (o_id > 0, FALSE); 1027 1028 if (g_id == 0) { 1029 df = DATA_FORMAT_OPERATION_UPDATE | DATA_FORMAT_OBJECT_ID; 1030 size = sizeof (guint32) * 4; 1031 } else { 1032 df = DATA_FORMAT_OPERATION_UPDATE | DATA_FORMAT_OBJECT_ID | DATA_FORMAT_GRAPH; 1033 size = sizeof (guint32) * 5; 1034 } 1035 1036 cur_block_maybe_expand (jwriter, size); 1037 1038 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), df); 1039 if (g_id > 0) { 1040 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), g_id); 1041 } 1042 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), s_id); 1043 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), p_id); 1044 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), o_id); 1045 1046 jwriter->cur_entry_amount++; 1047 jwriter->cur_block_len += size; 1048 1049 return TRUE; 1050 } 1051 1052 gboolean 1053 tracker_db_journal_append_update_statement_id (gint g_id, 1054 gint s_id, 1055 gint p_id, 1056 gint o_id) 1057 { 1058 if (current_transaction_format == TRANSACTION_FORMAT_ONTOLOGY) { 1059 return TRUE; 1060 } 1061 1062 return db_journal_writer_append_update_statement_id (&writer, 1063 g_id, s_id, p_id, o_id); 1064 } 1065 1066 static gboolean 1067 db_journal_writer_append_resource (JournalWriter *jwriter, 1068 gint s_id, 1069 const gchar *uri) 1070 { 1071 gint o_len; 1072 DataFormat df; 1073 gint size; 1074 1075 g_return_val_if_fail (jwriter->journal > 0, FALSE); 1076 1077 o_len = strlen (uri); 1078 df = DATA_FORMAT_RESOURCE_INSERT; 1079 size = (sizeof (guint32) * 2) + o_len + 1; 1080 1081 cur_block_maybe_expand (jwriter, size); 1082 1083 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), df); 1084 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), s_id); 1085 cur_setstr (jwriter->cur_block, &(jwriter->cur_pos), uri, o_len); 1086 1087 jwriter->cur_entry_amount++; 1088 jwriter->cur_block_len += size; 1089 1090 return TRUE; 1091 } 1092 1093 gboolean 1094 tracker_db_journal_append_resource (gint s_id, 1095 const gchar *uri) 1096 { 1097 gboolean ret; 1098 1099 g_return_val_if_fail (current_transaction_format != TRANSACTION_FORMAT_NONE, FALSE); 1100 1101 if (current_transaction_format == TRANSACTION_FORMAT_ONTOLOGY) { 1102 ret = db_journal_writer_append_resource (&ontology_writer, s_id, uri); 1103 } else { 1104 ret = db_journal_writer_append_resource (&writer, s_id, uri); 1105 } 1106 1107 return ret; 1108 } 1109 1110 gboolean 1111 tracker_db_journal_rollback_transaction (GError **error) 1112 { 1113 GError *n_error = NULL; 1114 1115 g_return_val_if_fail (writer.journal > 0, FALSE); 1116 g_return_val_if_fail (current_transaction_format != TRANSACTION_FORMAT_NONE, FALSE); 1117 1118 cur_block_kill (&writer); 1119 1120 if (current_transaction_format == TRANSACTION_FORMAT_ONTOLOGY) { 1121 cur_block_kill (&ontology_writer); 1122 db_journal_writer_shutdown (&ontology_writer, &n_error); 1123 } 1124 1125 if (n_error) { 1126 g_propagate_error (error, n_error); 1127 } 1128 1129 current_transaction_format = TRANSACTION_FORMAT_NONE; 1130 1131 return TRUE; 1132 } 1133 1134 gboolean 1135 tracker_db_journal_truncate (gsize new_size) 1136 { 1137 g_return_val_if_fail (writer.journal > 0, FALSE); 1138 1139 return (ftruncate (writer.journal, new_size) != -1); 1140 } 1141 1142 static gboolean 1143 db_journal_writer_commit_db_transaction (JournalWriter *jwriter, 1144 GError **error) 1145 { 1146 guint32 crc; 1147 guint begin_pos; 1148 guint size; 1149 guint offset; 1150 1151 g_return_val_if_fail (jwriter->journal > 0, FALSE); 1152 1153 begin_pos = 0; 1154 size = sizeof (guint32); 1155 offset = sizeof (guint32) * 3; 1156 1157 /* Expand by uint32 for the size check at the end of the entry */ 1158 cur_block_maybe_expand (jwriter, size); 1159 1160 jwriter->cur_block_len += size; 1161 1162 /* Write size and amount */ 1163 cur_setnum (jwriter->cur_block, &begin_pos, jwriter->cur_block_len); 1164 cur_setnum (jwriter->cur_block, &begin_pos, jwriter->cur_entry_amount); 1165 1166 /* Write size check to end of current journal data */ 1167 cur_setnum (jwriter->cur_block, &(jwriter->cur_pos), jwriter->cur_block_len); 1168 1169 /* Calculate CRC from entry triples start (i.e. without size, 1170 * amount and crc) until the end of the entry block. 1171 * 1172 * NOTE: the size check at the end is included in the CRC! 1173 */ 1174 crc = tracker_crc32 (jwriter->cur_block + offset, jwriter->cur_block_len - offset); 1175 cur_setnum (jwriter->cur_block, &begin_pos, crc); 1176 1177 if (!write_all_data (jwriter->journal, jwriter->cur_block, jwriter->cur_block_len, error)) { 1178 return FALSE; 1179 } 1180 1181 /* Update journal size */ 1182 jwriter->cur_size += jwriter->cur_block_len; 1183 1184 /* Clean up for next transaction */ 1185 cur_block_kill (jwriter); 1186 1187 return TRUE; 1188 } 1189 1190 gboolean 1191 tracker_db_journal_commit_db_transaction (GError **error) 1192 { 1193 gboolean ret; 1194 GError *n_error = NULL; 1195 1196 g_return_val_if_fail (current_transaction_format != TRANSACTION_FORMAT_NONE, FALSE); 1197 1198 if (current_transaction_format == TRANSACTION_FORMAT_ONTOLOGY) { 1199 ret = db_journal_writer_commit_db_transaction (&ontology_writer, &n_error); 1200 /* Coalesces the two error reports: */ 1201 db_journal_writer_shutdown (&ontology_writer, n_error ? NULL : &n_error); 1202 } else { 1203 ret = db_journal_writer_commit_db_transaction (&writer, &n_error); 1204 1205 #if GLIB_CHECK_VERSION (2, 24, 2) 1206 if (ret) { 1207 if (rotating_settings.do_rotating && (writer.cur_size > rotating_settings.chunk_size)) { 1208 ret = tracker_db_journal_rotate (&n_error); 1209 } 1210 } 1211 #endif /* GLib check */ 1212 } 1213 1214 if (n_error) { 1215 g_propagate_error (error, n_error); 1216 } 1217 1218 current_transaction_format = TRANSACTION_FORMAT_NONE; 1219 1220 return ret; 1221 } 1222 1223 gboolean 1224 tracker_db_journal_fsync (void) 1225 { 1226 g_return_val_if_fail (writer.journal > 0, FALSE); 1227 1228 return fsync (writer.journal) == 0; 1229 } 1230 1231 /* 1232 * Reader API 1233 */ 1234 1235 1236 static gchar* 1237 reader_get_next_filepath (JournalReader *jreader) 1238 { 1239 gchar *filename_open = NULL; 1240 gchar *test; 1241 1242 test = g_strdup_printf ("%s.%d", jreader->filename, jreader->current_file + 1); 1243 1244 if (g_file_test (test, G_FILE_TEST_EXISTS)) { 1245 jreader->current_file++; 1246 filename_open = test; 1247 } else { 1248 gchar *filename; 1249 GFile *dest_dir, *possible; 1250 1251 /* This is where chunks are being rotated to */ 1252 if (rotating_settings.rotate_to) { 1253 dest_dir = g_file_new_for_path (rotating_settings.rotate_to); 1254 } else { 1255 GFile *source; 1256 1257 /* keep compressed journal files in same directory */ 1258 source = g_file_new_for_path (test); 1259 dest_dir = g_file_get_parent (source); 1260 g_object_unref (source); 1261 } 1262 1263 filename = g_path_get_basename (test); 1264 g_free (test); 1265 test = filename; 1266 filename = g_strconcat (test, ".gz", NULL); 1267 g_free (test); 1268 possible = g_file_get_child (dest_dir, filename); 1269 g_object_unref (dest_dir); 1270 g_free (filename); 1271 1272 if (g_file_query_exists (possible, NULL)) { 1273 jreader->current_file++; 1274 filename_open = g_file_get_path (possible); 1275 } 1276 g_object_unref (possible); 1277 } 1278 1279 if (filename_open == NULL) { 1280 filename_open = g_strdup (jreader->filename); 1281 /* Last file is the active journal file */ 1282 jreader->current_file = 0; 1283 } 1284 1285 return filename_open; 1286 } 1287 1288 static gboolean 1289 db_journal_reader_init_file (JournalReader *jreader, 1290 const gchar *filename, 1291 GError **error) 1292 { 1293 #if GLIB_CHECK_VERSION (2, 24, 2) 1294 if (g_str_has_suffix (filename, ".gz")) { 1295 GFile *file; 1296 GInputStream *stream, *cstream; 1297 GConverter *converter; 1298 1299 file = g_file_new_for_path (filename); 1300 1301 stream = G_INPUT_STREAM (g_file_read (file, NULL, error)); 1302 g_object_unref (file); 1303 if (!stream) { 1304 return FALSE; 1305 } 1306 1307 jreader->underlying_stream = g_object_ref (stream); 1308 1309 if (jreader->underlying_stream_info) { 1310 g_object_unref (jreader->underlying_stream_info); 1311 jreader->underlying_stream_info = NULL; 1312 } 1313 1314 converter = G_CONVERTER (g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP)); 1315 cstream = g_converter_input_stream_new (stream, converter); 1316 g_object_unref (stream); 1317 g_object_unref (converter); 1318 1319 jreader->stream = g_data_input_stream_new (cstream); 1320 g_object_unref (cstream); 1321 } else { 1322 #endif /* GLib check */ 1323 jreader->file = g_mapped_file_new (filename, FALSE, error); 1324 1325 if (!jreader->file) { 1326 return FALSE; 1327 } 1328 1329 jreader->last_success = jreader->start = jreader->current = 1330 g_mapped_file_get_contents (jreader->file); 1331 1332 jreader->end = jreader->current + g_mapped_file_get_length (jreader->file); 1333 #if GLIB_CHECK_VERSION (2, 24, 2) 1334 } 1335 #endif /* GLib check */ 1336 1337 if (!journal_verify_header (jreader)) { 1338 g_set_error (error, TRACKER_DB_JOURNAL_ERROR, 1339 TRACKER_DB_JOURNAL_ERROR_BEGIN_OF_JOURNAL, 1340 "Damaged journal entry at begin of journal"); 1341 return FALSE; 1342 } 1343 1344 return TRUE; 1345 } 1346 1347 static gboolean 1348 db_journal_reader_init (JournalReader *jreader, 1349 gboolean global_reader, 1350 const gchar *filename, 1351 GError **error) 1352 { 1353 gchar *filename_used; 1354 gchar *filename_open; 1355 GError *n_error = NULL; 1356 1357 g_return_val_if_fail (jreader->file == NULL, FALSE); 1358 1359 /* Used mostly for testing */ 1360 if (G_UNLIKELY (filename)) { 1361 filename_used = g_strdup (filename); 1362 } else { 1363 filename_used = g_build_filename (g_get_user_data_dir (), 1364 "tracker", 1365 "data", 1366 TRACKER_DB_JOURNAL_FILENAME, 1367 NULL); 1368 } 1369 1370 jreader->filename = filename_used; 1371 1372 reader.current_file = 0; 1373 if (global_reader) { 1374 filename_open = reader_get_next_filepath (jreader); 1375 } else { 1376 filename_open = g_strdup (filename_used); 1377 } 1378 1379 jreader->type = TRACKER_DB_JOURNAL_START; 1380 1381 if (!db_journal_reader_init_file (jreader, filename_open, &n_error)) { 1382 if (!g_error_matches (n_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) && 1383 !g_error_matches (n_error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) { 1384 /* Do not set error if the file does not exist, just return FALSE */ 1385 1386 g_propagate_prefixed_error (error, 1387 n_error, 1388 "Could not create TrackerDBJournalReader for file '%s', ", 1389 jreader->filename); 1390 } else { 1391 g_error_free (n_error); 1392 } 1393 1394 g_free (filename_open); 1395 1396 tracker_db_journal_reader_shutdown (); 1397 return FALSE; 1398 } 1399 1400 g_free (filename_open); 1401 1402 return TRUE; 1403 } 1404 1405 gboolean 1406 tracker_db_journal_reader_init (const gchar *filename, 1407 GError **error) 1408 { 1409 gboolean ret; 1410 GError *n_error = NULL; 1411 1412 ret = db_journal_reader_init (&reader, TRUE, filename, &n_error); 1413 1414 if (n_error) { 1415 g_propagate_error (error, n_error); 1416 } 1417 1418 return ret; 1419 } 1420 1421 gboolean 1422 tracker_db_journal_reader_ontology_init (const gchar *filename, 1423 GError **error) 1424 { 1425 gchar *filename_used; 1426 gboolean result; 1427 GError *n_error = NULL; 1428 1429 /* Used mostly for testing */ 1430 if (G_UNLIKELY (filename)) { 1431 filename_used = g_strdup (filename); 1432 } else { 1433 filename_used = g_build_filename (g_get_user_data_dir (), 1434 "tracker", 1435 "data", 1436 TRACKER_DB_JOURNAL_ONTOLOGY_FILENAME, 1437 NULL); 1438 } 1439 1440 result = tracker_db_journal_reader_init (filename_used, &n_error); 1441 1442 g_free (filename_used); 1443 1444 if (n_error) { 1445 g_propagate_error (error, n_error); 1446 } 1447 1448 return result; 1449 } 1450 1451 gsize 1452 tracker_db_journal_reader_get_size_of_correct (void) 1453 { 1454 g_return_val_if_fail (reader.file != NULL, FALSE); 1455 1456 return (gsize) (reader.last_success - reader.start); 1457 } 1458 1459 static gboolean 1460 reader_next_file (GError **error) 1461 { 1462 gchar *filename_open; 1463 1464 filename_open = reader_get_next_filepath (&reader); 1465 1466 if (reader.stream) { 1467 g_object_unref (reader.stream); 1468 reader.stream = NULL; 1469 1470 g_object_unref (reader.underlying_stream); 1471 reader.underlying_stream = NULL; 1472 if (reader.underlying_stream_info) { 1473 g_object_unref (reader.underlying_stream_info); 1474 reader.underlying_stream_info = NULL; 1475 } 1476 1477 } else { 1478 g_mapped_file_unref (reader.file); 1479 reader.file = NULL; 1480 } 1481 1482 if (!db_journal_reader_init_file (&reader, filename_open, error)) { 1483 g_free (filename_open); 1484 tracker_db_journal_reader_shutdown (); 1485 return FALSE; 1486 } 1487 1488 g_free (filename_open); 1489 1490 reader.type = TRACKER_DB_JOURNAL_END_TRANSACTION; 1491 1492 reader.entry_begin = NULL; 1493 reader.entry_end = NULL; 1494 reader.amount_of_triples = 0; 1495 1496 return TRUE; 1497 } 1498 1499 static gboolean 1500 db_journal_reader_shutdown (JournalReader *jreader) 1501 { 1502 if (jreader->stream) { 1503 g_object_unref (jreader->stream); 1504 jreader->stream = NULL; 1505 g_object_unref (jreader->underlying_stream); 1506 jreader->underlying_stream = NULL; 1507 if (jreader->underlying_stream_info) { 1508 g_object_unref (jreader->underlying_stream_info); 1509 jreader->underlying_stream_info = NULL; 1510 } 1511 } else if (jreader->file) { 1512 #if GLIB_CHECK_VERSION(2,22,0) 1513 g_mapped_file_unref (jreader->file); 1514 #else 1515 g_mapped_file_free (jreader->file); 1516 #endif 1517 1518 jreader->file = NULL; 1519 } 1520 1521 g_free (jreader->filename); 1522 jreader->filename = NULL; 1523 1524 jreader->last_success = NULL; 1525 jreader->start = NULL; 1526 jreader->current = NULL; 1527 jreader->end = NULL; 1528 jreader->entry_begin = NULL; 1529 jreader->entry_end = NULL; 1530 jreader->amount_of_triples = 0; 1531 jreader->type = TRACKER_DB_JOURNAL_START; 1532 jreader->uri = NULL; 1533 jreader->g_id = 0; 1534 jreader->s_id = 0; 1535 jreader->p_id = 0; 1536 jreader->o_id = 0; 1537 jreader->object = NULL; 1538 1539 return TRUE; 1540 } 1541 1542 gboolean 1543 tracker_db_journal_reader_shutdown (void) 1544 { 1545 return db_journal_reader_shutdown (&reader); 1546 } 1547 1548 TrackerDBJournalEntryType 1549 tracker_db_journal_reader_get_type (void) 1550 { 1551 g_return_val_if_fail (reader.file != NULL || reader.stream != NULL, FALSE); 1552 1553 return reader.type; 1554 } 1555 1556 static gboolean 1557 db_journal_reader_next (JournalReader *jreader, gboolean global_reader, GError **error) 1558 { 1559 GError *inner_error = NULL; 1560 static gboolean debug_unchecked = TRUE; 1561 static gboolean slow_down = FALSE; 1562 1563 g_return_val_if_fail (jreader->file != NULL || jreader->stream != NULL, FALSE); 1564 1565 /* reset struct */ 1566 g_free (jreader->uri); 1567 jreader->uri = NULL; 1568 jreader->g_id = 0; 1569 jreader->s_id = 0; 1570 jreader->p_id = 0; 1571 jreader->o_id = 0; 1572 g_free (jreader->object); 1573 jreader->object = NULL; 1574 1575 /* 1576 * Visual layout of the data in the binary journal: 1577 * 1578 * [ 1579 * [magic] 1580 * [version] 1581 * [ 1582 * [entry 1583 * [size] 1584 * [amount] 1585 * [crc] 1586 * [time] 1587 * [id id id] 1588 * [id id string] 1589 * [id ...] 1590 * [size] 1591 * ] 1592 * [entry...] 1593 * [entry...] 1594 * ] 1595 * ] 1596 * 1597 * Note: We automatically start at the first entry, upon init 1598 * of the reader, we move past the [magic] and the [version]. 1599 */ 1600 1601 if (jreader->type == TRACKER_DB_JOURNAL_START || 1602 jreader->type == TRACKER_DB_JOURNAL_END_TRANSACTION) { 1603 /* Expect new transaction or end of file */ 1604 guint32 entry_size; 1605 guint32 entry_size_check; 1606 guint32 crc; 1607 guint32 crc_check; 1608 TransactionFormat t_kind; 1609 1610 1611 if (G_UNLIKELY (debug_unchecked)) { 1612 const gchar *test; 1613 1614 test = g_getenv ("TRACKER_DEBUG_MAKE_JOURNAL_READER_GO_VERY_SLOW"); 1615 if (g_strcmp0 (test, "yes") == 0) { 1616 slow_down = TRUE; 1617 } 1618 debug_unchecked = FALSE; 1619 } 1620 1621 if (G_UNLIKELY (slow_down)) { 1622 sleep (1); 1623 } 1624 1625 /* Check the end is not where we currently are */ 1626 if (journal_eof (jreader)) { 1627 /* Return FALSE as there is no further entry but 1628 * do not set error as it's not an error case. */ 1629 if (global_reader && jreader->current_file != 0) { 1630 if (reader_next_file (error)) { 1631 /* read first entry in next file */ 1632 return db_journal_reader_next (jreader, global_reader, error); 1633 } else { 1634 /* no more files */ 1635 return FALSE; 1636 } 1637 } else { 1638 return FALSE; 1639 } 1640 } 1641 1642 jreader->entry_begin = jreader->current; 1643 1644 /* Read the first uint32 which contains the size */ 1645 entry_size = journal_read_uint32 (jreader, &inner_error); 1646 if (inner_error) { 1647 g_propagate_error (error, inner_error); 1648 return FALSE; 1649 } 1650 1651 /* Check that entry is big enough for header and footer */ 1652 if (entry_size < 5 * sizeof (guint32)) { 1653 g_set_error (error, TRACKER_DB_JOURNAL_ERROR, 1654 TRACKER_DB_JOURNAL_ERROR_DAMAGED_JOURNAL_ENTRY, 1655 "Damaged journal entry, size %d < 5 * sizeof(guint32)", 1656 (gint) entry_size); 1657 return FALSE; 1658 } 1659 1660 /* Check that entry is smaller than the rest of the file. 1661 Very large entry_size could otherwise cause an overflow 1662 in entry_begin + entry_size below. */ 1663 if ((gint64) entry_size > (gint64) (jreader->end - jreader->entry_begin)) { 1664 g_set_error (error, TRACKER_DB_JOURNAL_ERROR, 1665 TRACKER_DB_JOURNAL_ERROR_DAMAGED_JOURNAL_ENTRY, 1666 "Damaged journal entry, size %u > %" G_GINT64_FORMAT " (rest of the file)", 1667 entry_size, (gint64)(jreader->end - jreader->entry_begin)); 1668 return FALSE; 1669 } 1670 1671 if (!jreader->stream) { 1672 /* Set the bounds for the entry */ 1673 jreader->entry_end = jreader->entry_begin + entry_size; 1674 1675 /* Check the end of the entry does not exceed the end 1676 * of the journal. 1677 */ 1678 if (jreader->end < jreader->entry_end) { 1679 g_set_error (error, TRACKER_DB_JOURNAL_ERROR, 1680 TRACKER_DB_JOURNAL_ERROR_DAMAGED_JOURNAL_ENTRY, 1681 "Damaged journal entry, end < entry end"); 1682 return FALSE; 1683 } 1684 1685 /* Read entry size check at the end of the entry */ 1686 entry_size_check = read_uint32 (jreader->entry_end - 4);
pointer targets in passing argument 1 of 'read_uint32' differ in signedness
(emitted by gcc)
1687 1688 if (entry_size != entry_size_check) { 1689 /* damaged journal entry */ 1690 g_set_error (error, TRACKER_DB_JOURNAL_ERROR, 1691 TRACKER_DB_JOURNAL_ERROR_DAMAGED_JOURNAL_ENTRY, 1692 "Damaged journal entry, %d != %d (entry size != entry size check)", 1693 entry_size, 1694 entry_size_check); 1695 return FALSE; 1696 } 1697 } 1698 1699 /* Read the amount of triples */ 1700 jreader->amount_of_triples = journal_read_uint32 (jreader, &inner_error); 1701 if (inner_error) { 1702 g_propagate_error (error, inner_error); 1703 return FALSE; 1704 } 1705 1706 /* Read the crc */ 1707 crc_check = journal_read_uint32 (jreader, &inner_error); 1708 if (inner_error) { 1709 g_propagate_error (error, inner_error); 1710 return FALSE; 1711 } 1712 1713 if (!jreader->stream) { 1714 // Maybe read in whole transaction in one buffer, so we can do CRC even without mmap (when reading compressed journals) 1715 // might this be too problematic memory-wise 1716 1717 /* Calculate the crc */ 1718 crc = tracker_crc32 (jreader->entry_begin + (sizeof (guint32) * 3), entry_size - (sizeof (guint32) * 3)); 1719 1720 /* Verify checksum */ 1721 if (crc != crc_check) { 1722 /* damaged journal entry */ 1723 g_set_error (error, TRACKER_DB_JOURNAL_ERROR, 1724 TRACKER_DB_JOURNAL_ERROR_DAMAGED_JOURNAL_ENTRY, 1725 "Damaged journal entry, 0x%.8x != 0x%.8x (crc32 failed)", 1726 crc, 1727 crc_check); 1728 return FALSE; 1729 } 1730 } 1731 1732 /* Read the timestamp */ 1733 jreader->time = journal_read_uint32 (jreader, &inner_error); 1734 if (inner_error) { 1735 g_propagate_error (error, inner_error); 1736 return FALSE; 1737 } 1738 1739 t_kind = journal_read_uint32 (jreader, &inner_error); 1740 if (inner_error) { 1741 g_propagate_error (error, inner_error); 1742 return FALSE; 1743 } 1744 1745 if (t_kind == TRANSACTION_FORMAT_DATA) 1746 jreader->type = TRACKER_DB_JOURNAL_START_TRANSACTION; 1747 else 1748 jreader->type = TRACKER_DB_JOURNAL_START_ONTOLOGY_TRANSACTION; 1749 1750 return TRUE; 1751 } else if (jreader->amount_of_triples == 0) { 1752 /* end of transaction */ 1753 1754 /* read redundant entry size at end of transaction */ 1755 journal_read_uint32 (jreader, &inner_error); 1756 if (inner_error) { 1757 g_propagate_error (error, inner_error); 1758 return FALSE; 1759 } 1760 1761 if (!jreader->stream) { 1762 if (jreader->current != jreader->entry_end) { 1763 /* damaged journal entry */ 1764 g_set_error (error, TRACKER_DB_JOURNAL_ERROR, 1765 TRACKER_DB_JOURNAL_ERROR_DAMAGED_JOURNAL_ENTRY, 1766 "Damaged journal entry, %p != %p (end of transaction with 0 triples)", 1767 jreader->current, 1768 jreader->entry_end); 1769 return FALSE; 1770 } 1771 } 1772 1773 jreader->type = TRACKER_DB_JOURNAL_END_TRANSACTION; 1774 jreader->last_success = jreader->current; 1775 1776 return TRUE; 1777 } else { 1778 DataFormat df; 1779 1780 df = journal_read_uint32 (jreader, &inner_error); 1781 if (inner_error) { 1782 g_propagate_error (error, inner_error); 1783 return FALSE; 1784 } 1785 1786 if (df == DATA_FORMAT_RESOURCE_INSERT) { 1787 jreader->type = TRACKER_DB_JOURNAL_RESOURCE; 1788 1789 jreader->s_id = journal_read_uint32 (jreader, &inner_error); 1790 if (inner_error) { 1791 g_propagate_error (error, inner_error); 1792 return FALSE; 1793 } 1794 1795 jreader->uri = journal_read_string (jreader, &inner_error); 1796 if (inner_error) { 1797 g_propagate_error (error, inner_error); 1798 return FALSE; 1799 } 1800 } else { 1801 if (df & DATA_FORMAT_OPERATION_DELETE) { 1802 if (df & DATA_FORMAT_OBJECT_ID) { 1803 jreader->type = TRACKER_DB_JOURNAL_DELETE_STATEMENT_ID; 1804 } else { 1805 jreader->type = TRACKER_DB_JOURNAL_DELETE_STATEMENT; 1806 } 1807 } else if (df & DATA_FORMAT_OPERATION_UPDATE) { 1808 if (df & DATA_FORMAT_OBJECT_ID) { 1809 jreader->type = TRACKER_DB_JOURNAL_UPDATE_STATEMENT_ID; 1810 } else { 1811 jreader->type = TRACKER_DB_JOURNAL_UPDATE_STATEMENT; 1812 } 1813 } else { 1814 if (df & DATA_FORMAT_OBJECT_ID) { 1815 jreader->type = TRACKER_DB_JOURNAL_INSERT_STATEMENT_ID; 1816 } else { 1817 jreader->type = TRACKER_DB_JOURNAL_INSERT_STATEMENT; 1818 } 1819 } 1820 1821 if (df & DATA_FORMAT_GRAPH) { 1822 /* named graph */ 1823 jreader->g_id = journal_read_uint32 (jreader, &inner_error); 1824 if (inner_error) { 1825 g_propagate_error (error, inner_error); 1826 return FALSE; 1827 } 1828 } else { 1829 /* default graph */ 1830 jreader->g_id = 0; 1831 } 1832 1833 jreader->s_id = journal_read_uint32 (jreader, &inner_error); 1834 if (inner_error) { 1835 g_propagate_error (error, inner_error); 1836 return FALSE; 1837 } 1838 1839 jreader->p_id = journal_read_uint32 (jreader, &inner_error); 1840 if (inner_error) { 1841 g_propagate_error (error, inner_error); 1842 return FALSE; 1843 } 1844 1845 if (df & DATA_FORMAT_OBJECT_ID) { 1846 jreader->o_id = journal_read_uint32 (jreader, &inner_error); 1847 if (inner_error) { 1848 g_propagate_error (error, inner_error); 1849 return FALSE; 1850 } 1851 } else { 1852 jreader->object = journal_read_string (jreader, &inner_error); 1853 if (inner_error) { 1854 g_propagate_error (error, inner_error); 1855 return FALSE; 1856 } 1857 } 1858 } 1859 1860 jreader->amount_of_triples--; 1861 return TRUE; 1862 } 1863 } 1864 1865 gboolean 1866 tracker_db_journal_reader_next (GError **error) 1867 { 1868 return db_journal_reader_next (&reader, TRUE, error); 1869 } 1870 1871 gboolean 1872 tracker_db_journal_reader_verify_last (const gchar *filename, 1873 GError **error) 1874 { 1875 guint32 entry_size_check; 1876 gboolean success = FALSE; 1877 JournalReader jreader = { 0 }; 1878 GError *n_error = NULL; 1879 1880 if (db_journal_reader_init (&jreader, FALSE, filename, &n_error)) { 1881 1882 if (jreader.end != jreader.current) { 1883 entry_size_check = read_uint32 (jreader.end - 4);
pointer targets in passing argument 1 of 'read_uint32' differ in signedness
(emitted by gcc)
1884 1885 if (jreader.end - entry_size_check < jreader.current) { 1886 g_set_error (error, TRACKER_DB_JOURNAL_ERROR, 1887 TRACKER_DB_JOURNAL_ERROR_DAMAGED_JOURNAL_ENTRY, 1888 "Damaged journal entry at end of journal"); 1889 db_journal_reader_shutdown (&jreader); 1890 return FALSE; 1891 } 1892 1893 jreader.current = jreader.end - entry_size_check; 1894 success = db_journal_reader_next (&jreader, FALSE, NULL); 1895 db_journal_reader_shutdown (&jreader); 1896 } else { 1897 success = TRUE; 1898 } 1899 } 1900 1901 if (n_error) { 1902 g_propagate_error (error, n_error); 1903 } 1904 1905 return success; 1906 } 1907 1908 gint64 1909 tracker_db_journal_reader_get_time (void) 1910 { 1911 return reader.time; 1912 } 1913 1914 gboolean 1915 tracker_db_journal_reader_get_resource (gint *id, 1916 const gchar **uri) 1917 { 1918 g_return_val_if_fail (reader.file != NULL || reader.stream != NULL, FALSE); 1919 g_return_val_if_fail (reader.type == TRACKER_DB_JOURNAL_RESOURCE, FALSE); 1920 1921 *id = reader.s_id; 1922 *uri = reader.uri; 1923 1924 return TRUE; 1925 } 1926 1927 gboolean 1928 tracker_db_journal_reader_get_statement (gint *g_id, 1929 gint *s_id, 1930 gint *p_id, 1931 const gchar **object) 1932 { 1933 g_return_val_if_fail (reader.file != NULL || reader.stream != NULL, FALSE); 1934 g_return_val_if_fail (reader.type == TRACKER_DB_JOURNAL_INSERT_STATEMENT || 1935 reader.type == TRACKER_DB_JOURNAL_DELETE_STATEMENT || 1936 reader.type == TRACKER_DB_JOURNAL_UPDATE_STATEMENT, 1937 FALSE); 1938 1939 if (g_id) { 1940 *g_id = reader.g_id; 1941 } 1942 *s_id = reader.s_id; 1943 *p_id = reader.p_id; 1944 *object = reader.object; 1945 1946 return TRUE; 1947 } 1948 1949 gboolean 1950 tracker_db_journal_reader_get_statement_id (gint *g_id, 1951 gint *s_id, 1952 gint *p_id, 1953 gint *o_id) 1954 { 1955 g_return_val_if_fail (reader.file != NULL || reader.stream != NULL, FALSE); 1956 g_return_val_if_fail (reader.type == TRACKER_DB_JOURNAL_INSERT_STATEMENT_ID || 1957 reader.type == TRACKER_DB_JOURNAL_DELETE_STATEMENT_ID || 1958 reader.type == TRACKER_DB_JOURNAL_UPDATE_STATEMENT_ID, 1959 FALSE); 1960 1961 if (g_id) { 1962 *g_id = reader.g_id; 1963 } 1964 *s_id = reader.s_id; 1965 *p_id = reader.p_id; 1966 *o_id = reader.o_id; 1967 1968 return TRUE; 1969 } 1970 1971 gdouble 1972 tracker_db_journal_reader_get_progress (void) 1973 { 1974 gdouble chunk = 0, total = 0, ret = 0; 1975 guint current_file; 1976 static guint total_chunks = 0; 1977 1978 current_file = reader.current_file == 0 ? total_chunks -1 : reader.current_file -1; 1979 1980 if (!rotating_settings.rotate_progress_flag) { 1981 gchar *test; 1982 GFile *dest_dir; 1983 gboolean cont = TRUE; 1984 1985 total_chunks = 0; 1986 1987 test = g_path_get_basename (reader.filename); 1988 1989 if (rotating_settings.rotate_to) { 1990 dest_dir = g_file_new_for_path (rotating_settings.rotate_to); 1991 } else { 1992 GFile *source; 1993 1994 /* keep compressed journal files in same directory */ 1995 source = g_file_new_for_path (test); 1996 dest_dir = g_file_get_parent (source); 1997 g_object_unref (source); 1998 } 1999 2000 g_free (test); 2001 2002 while (cont) { 2003 gchar *filename; 2004 GFile *possible; 2005 2006 test = g_strdup_printf ("%s.%d", reader.filename, total_chunks + 1); 2007 filename = g_path_get_basename (test); 2008 g_free (test); 2009 test = filename; 2010 filename = g_strconcat (test, ".gz", NULL); 2011 g_free (test); 2012 possible = g_file_get_child (dest_dir, filename); 2013 g_free (filename); 2014 if (g_file_query_exists (possible, NULL)) { 2015 total_chunks++; 2016 } else { 2017 cont = FALSE; 2018 } 2019 g_object_unref (possible); 2020 } 2021 2022 g_object_unref (dest_dir); 2023 rotating_settings.rotate_progress_flag = TRUE; 2024 } 2025 2026 if (total_chunks > 0) { 2027 total = ((gdouble) ((gdouble) current_file) / ((gdouble) total_chunks)); 2028 } 2029 2030 if (reader.start != 0) { 2031 /* When the last uncompressed part is being processed: */ 2032 gdouble percent = ((gdouble)(reader.end - reader.start)); 2033 ret = chunk = (((gdouble)(reader.current - reader.start)) / percent); 2034 } else if (reader.underlying_stream) { 2035 goffset size; 2036 2037 /* When a compressed part is being processed: */ 2038 2039 if (!reader.underlying_stream_info) { 2040 reader.underlying_stream_info = 2041 g_file_input_stream_query_info (G_FILE_INPUT_STREAM (reader.underlying_stream), 2042 G_FILE_ATTRIBUTE_STANDARD_SIZE, 2043 NULL, NULL); 2044 } 2045 2046 if (reader.underlying_stream_info) { 2047 size = g_file_info_get_size (reader.underlying_stream_info); 2048 ret = chunk = (gdouble) ((gdouble)g_seekable_tell (G_SEEKABLE (reader.underlying_stream))) / ((gdouble)size); 2049 } 2050 } 2051 2052 if (total_chunks > 0) { 2053 ret = total + (chunk / (gdouble) total_chunks); 2054 } 2055 2056 return ret; 2057 } 2058 2059 #if GLIB_CHECK_VERSION (2, 24, 2) 2060 static void 2061 on_chunk_copied_delete (GObject *source_object, 2062 GAsyncResult *res, 2063 gpointer user_data) 2064 { 2065 GOutputStream *ostream = G_OUTPUT_STREAM (source_object); 2066 GError *error = NULL; 2067 GFile *source = G_FILE (user_data); 2068 2069 g_output_stream_splice_finish (ostream, res, &error); 2070 if (!error) { 2071 g_file_delete (G_FILE (source), NULL, &error); 2072 } 2073 2074 g_object_unref (source); 2075 2076 if (error) { 2077 g_critical ("Error compressing rotated journal chunk: '%s'", error->message); 2078 g_error_free (error); 2079 } 2080 } 2081 2082 static gboolean 2083 tracker_db_journal_rotate (GError **error) 2084 { 2085 GFile *source, *destination; 2086 GFile *dest_dir; 2087 gchar *filename, *gzfilename; 2088 gchar *fullpath; 2089 GConverter *converter; 2090 GInputStream *istream; 2091 GOutputStream *ostream, *cstream; 2092 static gint max = 0; 2093 GError *n_error = NULL; 2094 gboolean ret; 2095 2096 #ifdef DISABLE_JOURNAL 2097 g_critical ("Journal is disabled, yet a journal function got called"); 2098 #endif 2099 2100 if (max == 0) { 2101 gchar *directory; 2102 GDir *journal_dir; 2103 const gchar *f_name; 2104 2105 directory = g_path_get_dirname (writer.journal_filename); 2106 journal_dir = g_dir_open (directory, 0, NULL); 2107 2108 f_name = g_dir_read_name (journal_dir); 2109 2110 while (f_name) { 2111 const gchar *ptr; 2112 guint cur; 2113 2114 if (f_name) { 2115 2116 if (!g_str_has_prefix (f_name, TRACKER_DB_JOURNAL_FILENAME ".")) { 2117 f_name = g_dir_read_name (journal_dir); 2118 continue; 2119 } 2120 2121 ptr = f_name + strlen (TRACKER_DB_JOURNAL_FILENAME "."); 2122 cur = atoi (ptr); 2123 max = MAX (cur, max); 2124 } 2125 2126 f_name = g_dir_read_name (journal_dir); 2127 } 2128 2129 g_dir_close (journal_dir); 2130 g_free (directory); 2131 } 2132 2133 tracker_db_journal_fsync (); 2134 2135 if (close (writer.journal) != 0) { 2136 g_set_error (error, TRACKER_DB_JOURNAL_ERROR, 2137 TRACKER_DB_JOURNAL_ERROR_COULD_NOT_CLOSE, 2138 "Could not close journal, %s", 2139 g_strerror (errno)); 2140 return FALSE; 2141 } 2142 2143 fullpath = g_strdup_printf ("%s.%d", writer.journal_filename, ++max); 2144 2145 g_rename (writer.journal_filename, fullpath); 2146 2147 /* Recalculate progress next time */ 2148 rotating_settings.rotate_progress_flag = FALSE; 2149 2150 source = g_file_new_for_path (fullpath); 2151 if (rotating_settings.rotate_to) { 2152 dest_dir = g_file_new_for_path (rotating_settings.rotate_to); 2153 } else { 2154 /* keep compressed journal files in same directory */ 2155 dest_dir = g_file_get_parent (source); 2156 } 2157 filename = g_path_get_basename (fullpath); 2158 gzfilename = g_strconcat (filename, ".gz", NULL); 2159 destination = g_file_get_child (dest_dir, gzfilename); 2160 g_object_unref (dest_dir); 2161 g_free (filename); 2162 g_free (gzfilename); 2163 2164 istream = G_INPUT_STREAM (g_file_read (source, NULL, NULL)); 2165 ostream = G_OUTPUT_STREAM (g_file_create (destination, 0, NULL, NULL)); 2166 converter = G_CONVERTER (g_zlib_compressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP, -1)); 2167 cstream = g_converter_output_stream_new (ostream, converter); 2168 g_output_stream_splice_async (cstream, istream, 0, 0, NULL, on_chunk_copied_delete, source); 2169 g_object_unref (istream); 2170 g_object_unref (ostream); 2171 g_object_unref (converter); 2172 g_object_unref (cstream); 2173 2174 g_object_unref (destination); 2175 2176 g_free (fullpath); 2177 2178 ret = db_journal_init_file (&writer, TRUE, &n_error); 2179 2180 if (n_error) { 2181 g_propagate_error (error, n_error); 2182 g_free (writer.journal_filename); 2183 writer.journal_filename = NULL; 2184 } 2185 2186 return ret; 2187 } 2188 #endif /* GLib check */ 2189 2190 #else /* DISABLE_JOURNAL */ 2191 void 2192 tracker_db_journal_set_rotating (gboolean do_rotating, 2193 gsize chunk_size, 2194 const gchar *rotate_to) 2195 { 2196 /* intentionally left blank, used for internal API compatibility */ 2197 } 2198 #endif /* DISABLE_JOURNAL */