1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 #ifdef HAVE_CONFIG_H 27 #include <config.h> 28 #endif 29 30 #include <locale.h> 31 #include <strings.h> 32 #include <string.h> 33 #include <unistd.h> 34 #include <libgen.h> 35 #include <stdlib.h> 36 #include <sys/types.h> 37 #include <dirent.h> 38 39 #include <glib.h> 40 #include <glib/gi18n.h> 41 42 #include "fsexam-header.h" 43 #include "fsexam-specialfile.h" 44 45 /* ------------- Compress file type implementation ------------ */ 46 typedef enum { 47 COMP_TARGZ = 0, 48 COMP_TARBZ2, 49 COMP_TAR, 50 COMP_ZIP, 51 COMP_Z, 52 }Compress_Type; 53 54 typedef struct { 55 gchar *result_path; /* used to generate hist path */ 56 gchar *search_path; /* used to generate hist search path */ 57 gchar *log_path; /* used to generate log_path */ 58 gint temp_dir_len; 59 }Compress_info; 60 61 static gchar *iso8859_locale = NULL; 62 const gchar *compress_pair[][3] = { 63 /* Type UNCOMPRESS COMPRESS */ 64 {".tar.gz", "LC_ALL=%s gzcat %s | tar -xf - 2>/dev/null", "LC_ALL=%s tar -cf - . | gzip > ../%s"}, 65 {".tar.bz2", "LC_ALL=%s bzcat %s | tar -xf - 2>/dev/null", "LC_ALL=%s tar -cf - . | bzip2 -z > ../%s"}, 66 {".tar", "LC_ALL=%s tar -xf %s 2>/dev/null", "LC_ALL=%s tar -cf - . > ../%s"}, 67 {".zip", "unzip -q %s 2>/dev/null", "zip -qr %s .; mv %s .."}, 68 {".tar.Z", "uncompress -c %s | tar -xf - 2>/dev/null", "tar -cf - . | compress -fc > ../%s"}, 69 }; 70 71 #define TARCMD "/usr/sfw/bin/gtar" 72 73 static gboolean fsexam_special_is_compress (const gchar *, Compress_Type *); 74 static gboolean compress_common_convert (const gchar *, 75 Compress_info *, 76 FSEXAM_setting *, 77 gboolean restore, 78 gboolean nameconvert); 79 static gboolean compress_convert_content (const gchar *, 80 Compress_info *, 81 FSEXAM_setting *, 82 gboolean restore); 83 84 static Compress_info * 85 compress_info_new (const gchar *result_path, 86 const gchar *search_path, 87 const gchar *log_path) 88 { 89 Compress_info *info = NULL; 90 91 if (NULL == result_path) 92 return NULL; 93 94 info = g_new0 (Compress_info, 1); 95 info->result_path = g_strdup (result_path); 96 info->search_path = g_strdup (search_path ? search_path : result_path); 97 info->log_path = g_strdup (log_path ? log_path : result_path); 98 99 return info; 100 } 101 102 static void 103 compress_info_free (Compress_info *info) 104 { 105 if (info == NULL) { 106 return; 107 } 108 109 g_free (info->result_path); 110 g_free (info->search_path); 111 g_free (info->log_path); 112 g_free (info); 113 114 return; 115 } 116 117 /* 118 * ensure $PWD is the directory of temparay directory 119 */ 120 static gchar * 121 compose_compress_cmd (Compress_Type type, const gchar *bname) 122 { 123 if (type == COMP_ZIP) { 124 return g_strdup_printf (compress_pair[type][2], bname, bname); 125 } 126 127 if (type <= COMP_TAR) { 128 return g_strdup_printf (compress_pair[type][2], iso8859_locale, bname); 129 } 130 131 return g_strdup_printf (compress_pair[type][2], bname); 132 } 133 134 /* 135 * Generate history path or log path for compress file. 136 * Please note that we may nested to handling compress file. so 137 * orig_compress_file 138 * may be in the form "/tmp/test/test.tar[src/test.tar][cmd/data.tar] 139 * ------------------------------- ------------ 140 * orig_compress_file fullpath - temp.. 141 * 142 * fullpath: the full path of compress file in question such as /tmp/a.tar 143 * 144 * The sequence of converting compress filename and content: 145 * regurlar: first file name , then file content. otherwise the log/hist 146 * info is not consistent with disk data. 147 * resotre ; first filecontent, then file name itself, otherwise 148 * can't search the history correctly 149 */ 150 static gchar * 151 compose_path (const gchar *fullpath, 152 Compress_info *info, 153 gboolean forhist, 154 gboolean restore) 155 { 156 const gchar *relative_path; 157 gchar *result = NULL; 158 #define URI_HEAD_LEN 7 159 160 if ((NULL == fullpath) || (NULL == info)) 161 return NULL; 162 163 relative_path = fullpath + info->temp_dir_len + 1; 164 165 if (forhist) { 166 /* 167 * Convert hist_path to uri, remove 'file://' then concat with 168 * relative_path 169 */ 170 gchar *uri; 171 172 uri = g_filename_to_uri ( 173 restore ? info->search_path : info->result_path, 174 NULL, 175 NULL); 176 result = g_strdup_printf ("%s\t%s", 177 uri + URI_HEAD_LEN, 178 relative_path); 179 180 g_free (uri); 181 }else { 182 gchar *esc_path = NULL; 183 184 if (! g_utf8_validate (relative_path, -1, NULL)) { 185 esc_path = g_strescape (relative_path, NULL); 186 } 187 188 if (g_utf8_validate (info->log_path, -1, NULL)) { 189 result = g_strdup_printf ("%s [%s]", 190 info->log_path, 191 esc_path ? esc_path : relative_path); 192 }else{ 193 gchar *uri = g_filename_to_uri (info->log_path, NULL, NULL); 194 result = g_strdup_printf ("%s [%s]", 195 uri, 196 esc_path ? esc_path : relative_path); 197 g_free (uri); 198 } 199 } 200 201 return result; 202 } 203 204 /* 205 * caller pass in orig_compress_file; 206 */ 207 static gboolean 208 compress_write_to_disk (FSEXAM_setting *setting, 209 const gchar *path, /* the path of current file */ 210 const gchar *origname, /* old base name */ 211 const gchar *utf8name, /* new base name */ 212 Compress_info *info, 213 short from_encoding, /* from encoding */ 214 short to_encoding, /* to encoding */ 215 gchar **actualname) /* return the actual used */ 216 { 217 static gchar oldname[PATH_MAX]; 218 static gchar newname[PATH_MAX]; 219 gchar *retname = NULL; 220 gchar *fname = NULL; 221 gchar *log_path = NULL; 222 gboolean ret = FALSE; 223 224 fsexam_errno = ERR_OK; 225 226 /* construct full old name and full new name */ 227 g_snprintf (oldname, PATH_MAX - 1, "%s/%s", path, origname); 228 g_snprintf (newname, PATH_MAX - 1, "%s/%s", path, utf8name); 229 230 if (g_file_test (newname, G_FILE_TEST_EXISTS)) { 231 fsexam_errno = ERR_NAME_EXIST; 232 fname = find_non_exist_name (newname); 233 234 if (fname == NULL) { 235 fsexam_errno = ERR_CANNOT_RENAME; 236 }else if (rename(oldname, fname) == 0){ 237 retname = g_strdup (basename (fname)); 238 ret = TRUE; 239 }else{ 240 fsexam_errno = ERR_CANNOT_RENAME; 241 } 242 }else{ 243 if (rename(oldname, newname) == 0){ 244 retname = g_strdup (utf8name); 245 ret = TRUE; 246 }else{ 247 fsexam_errno = ERR_CANNOT_RENAME; 248 } 249 } 250 251 /* history file; GUI vs. CLI */ 252 if ((ret) && (! (setting->flags & FSEXAM_SETTING_FLAGS_UNDO))) { 253 gboolean same_serial = TRUE; 254 if (setting->flags & FSEXAM_SETTING_FLAGS_DIFF_SERIAL) { 255 setting->flags &= ~FSEXAM_SETTING_FLAGS_DIFF_SERIAL; 256 same_serial = FALSE; 257 } 258 259 gchar *hist_path = compose_path (newname, info, TRUE, FALSE); 260 261 fsexam_history_put (setting->hist_info, 262 ConvNameSpecial, 263 hist_path, 264 from_encoding, 265 to_encoding, 266 same_serial); 267 268 g_free (hist_path); 269 } 270 271 ret ? ++setting->succ_num : ++setting->fail_num; 272 273 log_path = compose_path (ret ? newname : oldname, info, FALSE, FALSE); 274 275 /* log file */ 276 if (fsexam_errno == ERR_OK) { 277 gchar *msg = g_strdup_printf ("%s -> %s", 278 id2encoding (from_encoding), 279 id2encoding (to_encoding)); 280 fsexam_log_puts (setting->log_info, log_path, msg); 281 if (setting->display_msg) { 282 setting->display_msg (log_path, msg); 283 } 284 g_free (msg); 285 }else if (fsexam_errno == ERR_NAME_EXIST) { 286 fsexam_log_puts (setting->log_info, log_path, NULL); 287 if (setting->display_msg) { 288 setting->display_msg (log_path, fsexam_error_get_msg ()); 289 } 290 }else{ 291 fsexam_log_puts (setting->log_info, log_path, NULL); 292 if (setting->display_msg) { 293 setting->display_msg (log_path, fsexam_error_get_msg ()); 294 } 295 296 } 297 298 if (actualname != NULL) 299 *actualname = retname; //freed outside 300 else 301 g_free (retname); 302 303 g_free (log_path); 304 g_free (fname); 305 306 return ret; 307 } 308 309 /* 310 * Restore single file. 311 * 312 * Note that search path is in info directly, don't use compose any more. 313 * This is diff with non-restore operation. 314 */ 315 static gboolean 316 compress_restore_single_filename (FSEXAM_setting *setting, 317 const gchar *fullpath, 318 const gchar *dname, 319 const gchar *bname, 320 Compress_info *info, 321 gchar **newname) 322 { 323 gboolean ret = FALSE; 324 Hist_item *item = NULL; 325 gchar *converted_text = NULL; 326 gchar *log_path; 327 328 fsexam_errno = ERR_OK; 329 330 item = fsexam_history_search (setting->hist_info, info->search_path, TRUE); 331 332 if ((item == NULL) || (item->convtype != ConvNameSpecial)) { 333 fsexam_errno = ERR_HIST_NO_ITEM; 334 goto done; 335 } 336 337 converted_text = g_convert (bname, 338 strlen (bname), 339 id2encoding (item->from_encoding), 340 id2encoding (item->to_encoding), 341 NULL, 342 NULL, 343 NULL); 344 345 if (converted_text == NULL) { 346 fsexam_errno = ERR_CANNOT_CONVERT; 347 goto done; 348 } 349 350 ret = compress_write_to_disk (setting, 351 dname, 352 bname, 353 converted_text, 354 info, 355 item->to_encoding, 356 item->from_encoding, 357 newname); 358 359 g_free (converted_text); 360 361 return ret; 362 363 done: 364 log_path = compose_path (fullpath, info, FALSE, FALSE); 365 fsexam_log_puts (setting->log_info, log_path, NULL); 366 if (setting->display_msg) 367 setting->display_msg (log_path, fsexam_error_get_msg()); 368 369 g_free (log_path); 370 371 372 return ret; 373 } 374 375 /* 376 * 377 */ 378 static gboolean 379 compress_convert_single_filename (FSEXAM_setting *setting, 380 const gchar *fullpath, 381 const gchar *dname, /* info->log path, info->dname */ 382 const gchar *bname, 383 Compress_info *info, 384 gchar **newname) 385 { 386 Score score; 387 Encoding *encoding = NULL; 388 gboolean ret = FALSE; 389 390 fsexam_errno = ERR_OK; /* initialize fsexam_errno */ 391 392 if (setting->pref->auto_detect) { /* handle encoding auto detection */ 393 GList *detected_encoding = str_encoding_detect (bname, 394 DEFAULT_DETECTING_FLAG); 395 setting->pref->encode_list = fsexam_encoding_add_auto ( 396 setting->pref->encode_list, 397 detected_encoding); 398 auto_encoding_free (detected_encoding); 399 } 400 401 score = fsexam_encoding_decode (setting->pref->encode_list, 402 ConvName, 403 (char *)bname, 404 strlen(bname), 405 setting->pref->force); 406 407 408 if (setting->pref->dry_run){ /* dry run */ 409 //don't support dryrun 410 } else { /* real convert */ 411 gint index = 0; 412 gchar *actualname = NULL; 413 414 if ((score == FAIL) || (score == ORIGINAL)){ 415 fsexam_errno = (score == FAIL) ? ERR_NO_PROPER_ENCODING 416 : ERR_NAME_UTF8_ALREADY; 417 418 goto done; 419 } 420 421 if (setting->gold_index != -1) { 422 index = setting->gold_index; 423 } else if (setting->pref->auto_conversion) { 424 index = fsexam_encoding_get_first_index ( 425 setting->pref->encode_list); 426 } else { 427 index = setting->get_index (setting->pref->encode_list, TRUE); 428 } 429 430 if (-1 == index) { 431 goto cleanup; 432 } 433 434 encoding = (Encoding *)g_list_nth_data (setting->pref->encode_list, 435 index); 436 if (NULL == encoding){ 437 fsexam_errno = ERR_ENCODING_INDEX_INVALID; 438 goto done; 439 } 440 441 ret = compress_write_to_disk (setting, 442 dname, 443 bname, 444 encoding->u.converted_text, 445 info, 446 encoding->encodingID, 447 encoding2id ("UTF-8"), 448 &actualname); 449 450 if ((ret) && (newname)) { // Return new name 451 *newname = actualname; 452 }else{ 453 g_free (actualname); 454 } 455 456 return ret; 457 } 458 459 done: 460 if (fsexam_errno != ERR_OK && !setting->pref->dry_run) { 461 gchar *log_path; 462 463 log_path = compose_path (fullpath, info, FALSE, FALSE); 464 fsexam_log_puts (setting->log_info, log_path, NULL); 465 if (setting->display_msg) 466 setting->display_msg (log_path, fsexam_error_get_msg()); 467 468 g_free (log_path); 469 } 470 471 cleanup: 472 473 if (setting->pref->auto_detect) 474 setting->pref->encode_list = fsexam_encoding_remove_auto ( 475 setting->pref->encode_list); 476 477 return ret; 478 } 479 480 /* 481 * Convert the name of files in archive/compress type file 482 * And will handle flags 483 */ 484 static gboolean 485 compress_convert_filename (const gchar *fullpath, 486 Compress_info *info, 487 FSEXAM_setting *setting, 488 gboolean restore) 489 { 490 gchar *bname = NULL; 491 gchar *dname = NULL; 492 gchar *newname = NULL; 493 gchar *abs_path = NULL; 494 struct stat statbuf; 495 gboolean ret = FALSE; 496 gboolean need_free_newname = FALSE; 497 498 if ((NULL == fullpath) || (NULL == info) || (NULL == setting)) 499 return FALSE; 500 501 fsexam_errno = ERR_OK; 502 bname = g_path_get_basename (fullpath); 503 dname = g_path_get_dirname (fullpath); 504 505 if (lstat (fullpath, &statbuf) == -1) 506 fsexam_errno = ERR_FILE_NONEXIST; 507 else if (!(S_ISREG(statbuf.st_mode)) 508 && !(S_ISDIR(statbuf.st_mode)) && !(S_ISLNK(statbuf.st_mode))){ 509 fsexam_errno = ERR_FILE_TYPE_NOT_SUPPORT; 510 }else if ((! setting->pref->hidden) && (*bname == '.')){ 511 fsexam_errno = ERR_IGNORE_HIDDEN_FILE; 512 }else if ((!setting->pref->remote) 513 && (is_remote_file (setting->remote_path, fullpath))) { 514 fsexam_errno = ERR_IGNORE_REMOTE_FILE; 515 } 516 517 if (fsexam_errno != ERR_OK) { 518 gchar *log_path = compose_path (fullpath, info, FALSE, FALSE); 519 520 fsexam_log_puts (setting->log_info, log_path, NULL); 521 if (setting->display_msg) 522 setting->display_msg (log_path, fsexam_error_get_msg()); 523 g_free (log_path); 524 525 goto done; 526 } 527 528 if (restore && (strlen (fullpath) != info->temp_dir_len)) { 529 ret = compress_restore_single_filename (setting, 530 fullpath, 531 dname, 532 bname, 533 info, 534 &newname); 535 }else if (strlen (fullpath) != info->temp_dir_len) { 536 if ((!setting->pref->force) 537 && (str_isutf8 (bname, DEFAULT_DETECTING_FLAG))) { 538 gchar *log_path = compose_path (fullpath, info, FALSE, FALSE); 539 fsexam_errno = ERR_NAME_UTF8_ALREADY; 540 541 fsexam_log_puts (setting->log_info, log_path, NULL); 542 if (setting->display_msg) 543 setting->display_msg (log_path, fsexam_error_get_msg()); 544 g_free (log_path); 545 }else{ 546 ret = compress_convert_single_filename (setting, 547 fullpath, 548 dname, 549 bname, 550 info, 551 &newname); 552 } 553 } 554 555 if (ret && newname != NULL) { 556 abs_path = g_strdup_printf ("%s/%s", dname, newname); 557 need_free_newname = TRUE; 558 }else{ 559 abs_path = (gchar *)fullpath; 560 } 561 562 if (setting->flags & FSEXAM_SETTING_FLAGS_STOP) 563 goto done; 564 565 if (fsexam_special_is_compress (abs_path, NULL)){ 566 /* nested compress file */ 567 gchar *log_path = compose_path (abs_path, info, FALSE, FALSE); 568 gchar *result_path = compose_path (abs_path, info, TRUE, FALSE); 569 gchar *search_path; 570 571 if (restore) { 572 search_path = g_filename_to_uri (info->search_path, NULL, NULL); 573 574 }else{ 575 search_path = compose_path (abs_path, info, TRUE, TRUE); 576 } 577 578 Compress_info *new_info = compress_info_new (result_path, 579 search_path + URI_HEAD_LEN, 580 log_path); 581 582 g_free (log_path); 583 g_free (result_path); 584 g_free (search_path); 585 586 if (NULL == new_info) { 587 goto done; 588 } 589 590 compress_common_convert (abs_path, 591 new_info, 592 setting, 593 restore, 594 TRUE); 595 596 compress_info_free (new_info); 597 } else if (setting->pref->recursive 598 && S_ISDIR (statbuf.st_mode)) { /* Directory */ 599 const gchar *filename = NULL; 600 gchar *old_search_path = g_strdup (info->search_path); 601 GDir *dp = g_dir_open (abs_path, 0, NULL); 602 603 if (dp == NULL) 604 goto done; 605 606 while ((filename = g_dir_read_name (dp)) != NULL) { 607 gchar *childname = g_strdup_printf ("%s/%s", abs_path, filename); 608 609 if (restore) { 610 gchar *tmp; 611 tmp = g_strdup_printf ( 612 info->temp_dir_len == strlen (abs_path) ? "%s\t%s" 613 : "%s/%s", 614 old_search_path, 615 filename); 616 g_free (info->search_path); 617 info->search_path = tmp; 618 } 619 620 compress_convert_filename (childname, 621 info, 622 setting, 623 restore); 624 625 g_free (childname); 626 627 if (setting->flags & FSEXAM_SETTING_FLAGS_STOP) 628 break; 629 } 630 631 g_free (old_search_path); 632 g_dir_close (dp); 633 } 634 635 done: 636 if (need_free_newname) { 637 g_free (newname); 638 } 639 640 g_free (bname); 641 g_free (dname); 642 643 return ret; 644 } 645 646 /* 647 * Modify file content on the disk 648 */ 649 static gboolean 650 compress_write_back_contents (FSEXAM_setting *setting, 651 const gchar *fullpath, 652 Compress_info *info, 653 gchar *converted_contents, 654 short fid, 655 short tid) 656 { 657 gsize length; 658 gchar *hist_path = NULL; 659 gchar *log_path = NULL; 660 gboolean same_serial = TRUE; 661 gboolean need_free = FALSE; 662 gboolean ret = FALSE; 663 const gchar *from_encoding = id2encoding (fid); 664 const gchar *to_encoding = id2encoding (tid); 665 666 if (converted_contents == NULL) { 667 gchar *contents = NULL; 668 gboolean err; 669 670 err = g_file_get_contents (fullpath, &contents, &length, NULL); 671 672 if (err && !contents) { 673 fsexam_errno = ERR_CANNOT_READ; 674 goto done; 675 } else if (length == 0) { 676 fsexam_errno = ERR_EMPTY_FILE; 677 goto done; 678 } 679 680 converted_contents = g_convert (contents, 681 length, 682 to_encoding, 683 from_encoding, 684 NULL, 685 NULL, 686 NULL); 687 688 g_free (contents); 689 690 if (converted_contents == NULL) { 691 fsexam_errno = ERR_CANNOT_CONVERT; 692 goto done; 693 } 694 695 need_free = TRUE; 696 } 697 698 length = strlen (converted_contents); 699 700 /* Modify file contents on the disk */ 701 if (g_file_set_contents (fullpath, converted_contents, length, NULL)) { 702 ret = TRUE; 703 ++setting->succ_num; 704 }else{ 705 fsexam_errno = ERR_CANNOT_WRITE; 706 ++setting->fail_num; 707 goto done; 708 } 709 710 711 if (setting->flags & FSEXAM_SETTING_FLAGS_UNDO) { 712 goto done; 713 } 714 715 if (setting->flags & FSEXAM_SETTING_FLAGS_DIFF_SERIAL) { 716 setting->flags &= ~FSEXAM_SETTING_FLAGS_DIFF_SERIAL; 717 same_serial = FALSE; 718 } 719 720 hist_path = compose_path (fullpath, info, TRUE, FALSE); 721 722 fsexam_history_put (setting->hist_info, 723 ConvContentSpecial, 724 hist_path, 725 fid, 726 tid, 727 same_serial); 728 729 done: 730 log_path = compose_path (fullpath, info, FALSE, FALSE); 731 732 /* log file */ 733 if (fsexam_errno == ERR_OK) { 734 gchar *msg = g_strdup_printf (_("[Content] %s -> %s"), 735 from_encoding, 736 to_encoding); 737 fsexam_log_puts (setting->log_info, log_path, msg); 738 if (setting->display_msg) { 739 setting->display_msg (log_path, msg); 740 } 741 g_free (msg); 742 }else{ 743 fsexam_log_puts (setting->log_info, log_path, NULL); 744 if (setting->display_msg) { 745 setting->display_msg (log_path, fsexam_error_get_msg ()); 746 } 747 } 748 749 750 g_free (hist_path); 751 g_free (log_path); 752 753 if (need_free) 754 g_free (converted_contents); 755 756 return ret; 757 } 758 759 /* 760 * Restore single file's content. 761 */ 762 static gboolean 763 compress_restore_single_file_content (const gchar *fullpath, 764 Compress_info *info, 765 FSEXAM_setting *setting) 766 { 767 gboolean ret = FALSE; 768 gchar *hist_path = NULL; 769 gchar *log_path = NULL; 770 Hist_item *item = NULL; 771 772 ++setting->total_num; 773 fsexam_errno = ERR_OK; 774 775 hist_path = compose_path (fullpath, info, TRUE, TRUE); 776 item = fsexam_history_search (setting->hist_info, hist_path, FALSE); 777 778 if ((item == NULL) || (item->convtype != ConvContentSpecial)) { 779 fsexam_errno = ERR_HIST_NO_ITEM; 780 goto done; 781 } 782 783 ret = compress_write_back_contents (setting, 784 fullpath, 785 info, /* Compress info struct */ 786 NULL, /* contents pointer */ 787 item->to_encoding, 788 item->from_encoding); 789 790 goto cleanup; 791 792 done: 793 log_path = compose_path (fullpath, info, FALSE, FALSE); 794 795 fsexam_log_puts (setting->log_info, log_path, NULL); 796 if (setting->display_msg) 797 setting->display_msg (log_path, fsexam_error_get_msg()); 798 799 cleanup: 800 g_free (hist_path); 801 g_free (log_path); 802 803 return ret; 804 } 805 806 /* 807 * Convert single one file's content. Don't care flags 808 */ 809 static gboolean 810 compress_convert_single_file_content (const gchar *fullpath, 811 Compress_info *info, 812 FSEXAM_setting *setting) 813 { 814 Score score; 815 Encoding *encoding = NULL; 816 gboolean err; 817 gchar *sample_contents = NULL; 818 gchar *contents = NULL; 819 gsize length; 820 gint index = 0; 821 gboolean need_free_contents = FALSE; 822 gboolean ret = FALSE; 823 824 fsexam_errno = ERR_OK; 825 ++setting->total_num; 826 827 if (! file_validate_for_contentconv (fullpath, setting)) { 828 /* Don't need convert current file's content */ 829 goto done; 830 } 831 832 /* handle encoding auto detection, plain text need this */ 833 if (setting->pref->auto_detect) { 834 GList *detected_encoding; 835 836 detected_encoding = file_encoding_detect (fullpath, 837 DEFAULT_DETECTING_FLAG); 838 setting->pref->encode_list = fsexam_encoding_add_auto ( 839 setting->pref->encode_list, 840 detected_encoding); 841 auto_encoding_free (detected_encoding); 842 } 843 844 if (! fsexam_is_plain_text (fullpath, setting)) { 845 fsexam_errno = ERR_FILE_TYPE_NOT_SUPPORT; 846 goto done; 847 } 848 849 /* plain text now */ 850 err = g_file_get_contents (fullpath, &contents, &length, NULL); 851 if (err && !contents) { 852 fsexam_errno = ERR_CANNOT_READ; 853 goto done; 854 } else if (length == 0) { 855 fsexam_errno = ERR_EMPTY_FILE; 856 goto done; 857 } 858 859 sample_contents = get_sample_text (contents, &length); 860 score = fsexam_encoding_decode (setting->pref->encode_list, 861 ConvContent, 862 sample_contents, 863 length, 864 setting->pref->force); 865 866 g_free (contents); 867 g_free (sample_contents); 868 869 need_free_contents = TRUE; /* free contents in encoding_list */ 870 871 if (setting->pref->dry_run) { 872 /* Don't support dry run for special file */ 873 }else{ 874 if ((score == FAIL) || (score == ORIGINAL)){ 875 fsexam_errno = (score == FAIL) ? ERR_NO_PROPER_ENCODING 876 : ERR_CONTENT_UTF8_ALREADY; 877 goto done; 878 } 879 880 if (setting->gold_index != -1) { 881 index = setting->gold_index; 882 } else if (setting->pref->auto_conversion) { 883 index = fsexam_encoding_get_first_index ( 884 setting->pref->encode_list); 885 } else { 886 index = setting->get_index (setting->pref->encode_list, FALSE); 887 } 888 889 if (index == -1) { 890 goto cleanup; 891 } 892 893 encoding = (Encoding *)g_list_nth_data (setting->pref->encode_list, 894 index); 895 if (NULL == encoding){ 896 fsexam_errno = ERR_ENCODING_INDEX_INVALID; 897 goto done; 898 } 899 900 ret = compress_write_back_contents (setting, 901 fullpath, 902 info, 903 NULL, /* contents pointer */ 904 encoding->encodingID, 905 encoding2id ("UTF-8")); 906 } 907 908 done: 909 if (fsexam_errno != ERR_OK && !setting->pref->dry_run) { 910 gchar *log_path = compose_path (fullpath, info, FALSE, FALSE); 911 912 fsexam_log_puts (setting->log_info, log_path, NULL); 913 if (setting->display_msg) 914 setting->display_msg (log_path, fsexam_error_get_msg()); 915 916 g_free (log_path); 917 } 918 919 cleanup: 920 if (setting->pref->auto_detect) 921 setting->pref->encode_list = fsexam_encoding_remove_auto ( 922 setting->pref->encode_list); 923 924 if (need_free_contents) 925 fsexam_encoding_cleanup_content (setting->pref->encode_list); 926 927 return ret; 928 } 929 930 /* 931 * Convert the content of unarchive/uncompress files. 932 * don't handle symlink for special type file. 933 */ 934 static gboolean 935 compress_convert_content (const gchar *fullpath, 936 Compress_info *info, 937 FSEXAM_setting *setting, 938 gboolean restore) 939 { 940 gboolean ret = FALSE; 941 gchar *abs_path = get_abs_path (fullpath); 942 struct stat statbuf; 943 944 if ((abs_path == NULL) || (setting == NULL) || (info == NULL)) 945 return FALSE; 946 947 if (lstat (abs_path, &statbuf) == -1) { 948 fsexam_errno = ERR_CANNOT_OPEN; 949 goto done; 950 } 951 952 if (fsexam_special_is_compress (abs_path, NULL)){ 953 /* nested compress file */ 954 gchar *search_path = compose_path (abs_path, info, TRUE, TRUE); 955 gchar *result_path = compose_path (abs_path, info, TRUE, FALSE); 956 gchar *log_path = compose_path (abs_path, info, FALSE, FALSE); 957 Compress_info *new_info = compress_info_new (result_path, 958 search_path, 959 log_path); 960 if (NULL == new_info) { 961 goto done; 962 } 963 964 compress_common_convert (abs_path, 965 new_info, 966 setting, 967 restore, 968 FALSE); 969 970 compress_info_free (new_info); 971 }else if (S_ISREG (statbuf.st_mode)) { /* regular file */ 972 if (restore) { 973 compress_restore_single_file_content (abs_path, 974 info, 975 setting); 976 }else{ 977 compress_convert_single_file_content (abs_path, 978 info, 979 setting); 980 } 981 } else if (setting->pref->recursive 982 && S_ISDIR (statbuf.st_mode)) { /* Directory */ 983 const gchar *filename = NULL; 984 GDir *dp = g_dir_open (abs_path, 0, NULL); 985 986 if (dp == NULL) 987 goto done; 988 989 while ((filename = g_dir_read_name (dp)) != NULL) { 990 gchar *childname = g_strdup_printf ("%s/%s", abs_path, filename); 991 992 compress_convert_content (childname, 993 info, 994 setting, 995 restore); 996 997 g_free (childname); 998 999 if (setting->flags && FSEXAM_SETTING_FLAGS_STOP) 1000 break; 1001 } 1002 1003 g_dir_close (dp); 1004 } 1005 1006 done: 1007 g_free (abs_path); 1008 1009 return ret; 1010 } 1011 1012 /* 1013 * Whether give file is supported archive/compress file or not 1014 */ 1015 static gboolean 1016 fsexam_special_is_compress (const gchar *filename, Compress_Type *type) 1017 { 1018 int i; 1019 1020 if (NULL == filename) { 1021 return FALSE; 1022 } 1023 1024 for (i = 0; i < sizeof (compress_pair)/sizeof (compress_pair[0]); i++) { 1025 if (g_str_has_suffix (filename, compress_pair[i][0])) { 1026 if (type != NULL) 1027 *type = (Compress_Type) i; 1028 1029 return TRUE; 1030 } 1031 } 1032 1033 return FALSE; 1034 } 1035 1036 static gboolean 1037 get_iso8859_locale (FSEXAM_setting *setting) 1038 { 1039 static gboolean first = TRUE; 1040 1041 if (first) { 1042 char *old_locale = setlocale (LC_ALL, NULL); 1043 1044 if ((setlocale (LC_ALL, "en_US.ISO8859-1")) != NULL) { 1045 iso8859_locale = "en_US.ISO8859-1"; 1046 }else if ((setlocale (LC_ALL, "fr_FR.ISO8859-1")) != NULL) { 1047 iso8859_locale = "fr_FR.ISO8859-1"; 1048 }else if ((setlocale (LC_ALL, "de_DE.ISO8859-1")) != NULL) { 1049 iso8859_locale = "de_DE.ISO8859-1"; 1050 }else if ((setlocale (LC_ALL, "es_ES.ISO8859-1")) != NULL) { 1051 iso8859_locale = "es_ES.ISO8859-1"; 1052 }else if ((setlocale (LC_ALL, "it_IT.ISO8859-1")) != NULL) { 1053 iso8859_locale = "it_IT.ISO8859-1"; 1054 }else if ((setlocale (LC_ALL, "sv_SE.ISO8859-1")) != NULL) { 1055 iso8859_locale = "sv_SE.ISO8859-1"; 1056 }else{ 1057 iso8859_locale = NULL; 1058 } 1059 1060 /* reset locale */ 1061 if (old_locale != NULL) 1062 setlocale (LC_ALL, old_locale); 1063 1064 first = FALSE; 1065 } 1066 1067 if (iso8859_locale == NULL && setting->display_msg) 1068 setting->display_msg (NULL, _("Can not run tar command due to lack of iso8859-1 locale, please see fsexam(1) man page for more info.")); 1069 1070 return (iso8859_locale != NULL); 1071 } 1072 1073 static gboolean 1074 run_cmd (gchar **argv, gchar **envp, FSEXAM_setting *setting) 1075 { 1076 FILE *fp = NULL; 1077 gchar tmp[200]; 1078 GError *error = NULL; 1079 gboolean ret = FALSE; 1080 gint child_stderr; 1081 1082 if (! g_spawn_async_with_pipes (NULL, argv, envp, 0, 1083 NULL, NULL, NULL, NULL, 1084 NULL, 1085 &child_stderr, 1086 &error)) { 1087 setting->display_msg (NULL, error->message); 1088 g_error_free (error); 1089 goto DONE; 1090 } 1091 1092 fp = fdopen (child_stderr, "r"); 1093 if (fp == NULL) { 1094 goto DONE; 1095 } 1096 1097 if (fgets (tmp, sizeof (tmp), fp) != NULL) { 1098 setting->display_msg (NULL, tmp); 1099 goto DONE; 1100 } 1101 1102 ret = TRUE; 1103 1104 DONE: 1105 if (fp != NULL) 1106 fclose (fp); 1107 1108 return ret; 1109 } 1110 1111 static gboolean 1112 uncompress_pre (const gchar *fullpath, const gchar *tmpdir, 1113 FSEXAM_setting *setting) 1114 { 1115 gchar **argv = NULL; 1116 gboolean ret = FALSE; 1117 1118 if (! get_iso8859_locale (setting)) { 1119 return FALSE; 1120 } 1121 1122 /* cp target file into current directory */ 1123 argv = g_malloc (sizeof (gchar **) * 4); 1124 argv[0] = "/usr/bin/cp"; 1125 argv[1] = (gchar *)fullpath; 1126 argv[2] = (gchar *)tmpdir; 1127 argv[3] = NULL; 1128 1129 if (! run_cmd (argv, NULL, setting)) 1130 goto DONE; 1131 1132 ret = TRUE; 1133 1134 DONE: 1135 g_free (argv); 1136 1137 return ret; 1138 } 1139 1140 static gboolean 1141 delete_files (const gchar *filename, FSEXAM_setting *setting) 1142 { 1143 gchar **argv = NULL; 1144 gboolean ret = FALSE; 1145 1146 /* rm target file into current directory */ 1147 argv = g_malloc (sizeof (gchar **) * 4); 1148 argv[0] = "/usr/bin/rm"; 1149 argv[1] = "-rf"; 1150 argv[2] = (gchar *)filename; 1151 argv[3] = NULL; 1152 1153 if (! run_cmd (argv, NULL, setting)) 1154 goto DONE; 1155 1156 ret = TRUE; 1157 1158 DONE: 1159 g_free (argv); 1160 1161 return ret; 1162 } 1163 1164 static gboolean 1165 uncompress_post (const gchar *filename, FSEXAM_setting *setting) 1166 { 1167 if (! delete_files (filename, setting)) 1168 return FALSE; 1169 1170 return TRUE; 1171 } 1172 1173 static gboolean 1174 uncompress_bz2 (const gchar *fullpath, const gchar *tmpdir, 1175 FSEXAM_setting *setting) 1176 { 1177 gchar *bname = NULL; 1178 gchar **argv = NULL; 1179 gchar **envp = NULL; 1180 gboolean ret = FALSE; 1181 1182 if (! uncompress_pre (fullpath, tmpdir, setting)) { 1183 return FALSE; 1184 } 1185 1186 bname = g_path_get_basename (fullpath); 1187 1188 argv = g_malloc (sizeof (gchar **) * 4); 1189 argv[0] = "/usr/bin/bunzip2"; 1190 argv[1] = bname; 1191 argv[2] = NULL; 1192 1193 /* bunzip2 */ 1194 if (! run_cmd (argv, NULL, setting)) { 1195 goto DONE; 1196 } 1197 1198 /* untar */ 1199 *(bname + strlen (bname) - 4) = '\0'; /* 4 is strlen(".bz2") */ 1200 argv[0] = TARCMD; 1201 argv[1] = "-xf"; 1202 argv[2] = bname; 1203 argv[3] = NULL; 1204 1205 envp = g_malloc (sizeof (gchar **) * 2); 1206 envp[0] = iso8859_locale; 1207 envp[1] = NULL; 1208 1209 if (! run_cmd (argv, envp, setting)) 1210 goto DONE; 1211 1212 /* delete bname */ 1213 if (! uncompress_post (bname, setting)) 1214 goto DONE; 1215 1216 1217 ret = TRUE; 1218 1219 DONE: 1220 g_free (bname); 1221 g_free (argv); 1222 g_free (envp); 1223 1224 return ret; 1225 } 1226 1227 static gboolean 1228 uncompress_gz (const gchar *fullpath, const gchar *tmpdir, 1229 FSEXAM_setting *setting) 1230 { 1231 gchar *bname = NULL; 1232 gchar **argv = NULL; 1233 gchar **envp = NULL; 1234 gboolean ret = FALSE; 1235 1236 if (! uncompress_pre (fullpath, tmpdir, setting)) { 1237 return FALSE; 1238 } 1239 1240 bname = g_path_get_basename (fullpath); 1241 1242 argv = g_malloc (sizeof (gchar **) * 4); 1243 argv[0] = "/usr/bin/gunzip"; 1244 argv[1] = bname; 1245 argv[2] = NULL; 1246 1247 /* bunzip2 */ 1248 if (! run_cmd (argv, NULL, setting)) { 1249 goto DONE; 1250 } 1251 1252 /* untar */ 1253 *(bname + strlen (bname) - 3) = '\0'; /* 3 is strlen(".gz") */ 1254 argv[0] = TARCMD; 1255 argv[1] = "-xf"; 1256 argv[2] = bname; 1257 argv[3] = NULL; 1258 1259 envp = g_malloc (sizeof (gchar **) * 2); 1260 envp[0] = iso8859_locale; 1261 envp[1] = NULL; 1262 1263 if (! run_cmd (argv, envp, setting)) 1264 goto DONE; 1265 1266 /* delete bname */ 1267 if (! uncompress_post (bname, setting)) 1268 goto DONE; 1269 1270 1271 ret = TRUE; 1272 1273 DONE: 1274 g_free (bname); 1275 g_free (argv); 1276 g_free (envp); 1277 1278 return ret; 1279 } 1280 1281 static gboolean 1282 uncompress_tar (const gchar *fullpath, FSEXAM_setting *setting) 1283 { 1284 gchar **argv = NULL; 1285 gchar **envp = NULL; 1286 gboolean ret = FALSE; 1287 1288 if (! get_iso8859_locale (setting)) 1289 return FALSE; 1290 1291 argv = g_malloc (sizeof (gchar **) * 4); 1292 argv[0] = TARCMD; 1293 argv[1] = "-xf"; 1294 argv[2] = (gchar *)fullpath; 1295 argv[3] = NULL; 1296 1297 envp = g_malloc (sizeof (gchar **) * 2); 1298 envp[0] = iso8859_locale; 1299 envp[1] = NULL; 1300 1301 if (! run_cmd (argv, envp, setting)) 1302 goto DONE; 1303 1304 ret = TRUE; 1305 1306 DONE: 1307 g_free (argv); 1308 g_free (envp); 1309 1310 return ret; 1311 } 1312 1313 static gboolean 1314 uncompress_unzip (const gchar *fullpath, FSEXAM_setting *setting) 1315 { 1316 gchar **argv = NULL; 1317 gboolean ret = FALSE; 1318 1319 argv = g_malloc (sizeof (gchar **) * 4); 1320 argv[0] = "/usr/bin/unzip"; 1321 argv[1] = "-q"; 1322 argv[2] = (gchar *)fullpath; 1323 argv[3] = NULL; 1324 1325 if (! run_cmd (argv, NULL, setting)) 1326 goto DONE; 1327 1328 ret = TRUE; 1329 1330 DONE: 1331 g_free (argv); 1332 1333 return ret; 1334 } 1335 1336 static gboolean 1337 uncompress_Z (const gchar *fullpath, const gchar *tmpdir, 1338 FSEXAM_setting *setting) 1339 { 1340 gchar *bname = NULL; 1341 gchar **argv = NULL; 1342 gchar **envp = NULL; 1343 gboolean ret = FALSE; 1344 1345 if (! uncompress_pre (fullpath, tmpdir, setting)) { 1346 return FALSE; 1347 } 1348 1349 bname = g_path_get_basename (fullpath); 1350 1351 argv = g_malloc (sizeof (gchar **) * 4); 1352 argv[0] = "/usr/bin/uncompress"; 1353 argv[1] = "-c"; 1354 argv[2] = bname; 1355 argv[3] = NULL; 1356 1357 /* bunzip2 */ 1358 if (! run_cmd (argv, NULL, setting)) { 1359 goto DONE; 1360 } 1361 1362 /* untar */ 1363 *(bname + strlen (bname) - 2) = '\0'; /* 2 is strlen(".Z") */ 1364 argv[0] = TARCMD; 1365 argv[1] = "-xf"; 1366 argv[2] = bname; 1367 argv[3] = NULL; 1368 1369 envp = g_malloc (sizeof (gchar **) * 2); 1370 envp[0] = iso8859_locale; 1371 envp[1] = NULL; 1372 1373 if (! run_cmd (argv, envp, setting)) 1374 goto DONE; 1375 1376 /* delete bname */ 1377 if (! uncompress_post (bname, setting)) 1378 goto DONE; 1379 1380 1381 ret = TRUE; 1382 1383 DONE: 1384 g_free (bname); 1385 g_free (argv); 1386 g_free (envp); 1387 1388 return ret; 1389 } 1390 1391 /* 1392 * Uncompress .bz2, .gz, .zip, .Z 1393 */ 1394 static gboolean 1395 fsexam_uncompress (const gchar *fullpath, const gchar *tmpdir, 1396 Compress_Type type, FSEXAM_setting *setting) 1397 { 1398 /* uncompress */ 1399 if (type == COMP_TARGZ) { 1400 return uncompress_gz (fullpath, tmpdir, setting); 1401 } else if (type == COMP_TARBZ2) { 1402 return uncompress_bz2 (fullpath, tmpdir, setting); 1403 } else if (type == COMP_TAR) { 1404 return uncompress_tar (fullpath, setting); 1405 } else if (type == COMP_ZIP) { 1406 return uncompress_unzip (fullpath, setting); 1407 } else if (type == COMP_Z) { 1408 return uncompress_Z (fullpath, tmpdir, setting); 1409 } else { 1410 if (setting->display_msg) 1411 setting->display_msg (fullpath, 1412 _("Don't support this file type")); 1413 } 1414 1415 return FALSE; 1416 } 1417 1418 static gboolean 1419 compress_bz2 (const gchar *target_name, FSEXAM_setting *setting) 1420 { 1421 gchar **argv = NULL; 1422 gboolean ret = FALSE; 1423 1424 argv = g_malloc (sizeof (gchar **) * 5); 1425 argv[0] = TARCMD; 1426 argv[1] = "-cjf"; 1427 argv[2] = (gchar *)target_name; 1428 argv[3] = "."; 1429 argv[4] = NULL; 1430 1431 if (! run_cmd (argv, NULL, setting)) { 1432 goto DONE; 1433 } 1434 1435 ret = TRUE; 1436 1437 DONE: 1438 g_free (argv); 1439 1440 return ret; 1441 } 1442 1443 static gboolean 1444 compress_tar (const gchar *target_name, FSEXAM_setting *setting) 1445 { 1446 gchar **argv = NULL; 1447 gboolean ret = FALSE; 1448 1449 argv = g_malloc (sizeof (gchar **) * 5); 1450 argv[0] = TARCMD; 1451 argv[1] = "-cf"; 1452 argv[2] = (gchar *)target_name; 1453 argv[3] = "."; 1454 argv[4] = NULL; 1455 1456 if (! run_cmd (argv, NULL, setting)) { 1457 goto DONE; 1458 } 1459 1460 ret = TRUE; 1461 1462 DONE: 1463 g_free (argv); 1464 1465 return ret; 1466 } 1467 1468 static gboolean 1469 compress_Z (const gchar *target_name, FSEXAM_setting *setting) 1470 { 1471 gchar **argv = NULL; 1472 gboolean ret = FALSE; 1473 1474 argv = g_malloc (sizeof (gchar **) * 5); 1475 argv[0] = TARCMD; 1476 argv[1] = "-cZf"; 1477 argv[2] = (gchar *)target_name; 1478 argv[3] = "."; 1479 argv[4] = NULL; 1480 1481 if (! run_cmd (argv, NULL, setting)) { 1482 goto DONE; 1483 } 1484 1485 ret = TRUE; 1486 1487 DONE: 1488 g_free (argv); 1489 1490 return ret; 1491 } 1492 1493 /* 1494 * zip in the current directory, then move to target dir. 1495 * Otherwise zip(1) will append the new files into old file 1496 */ 1497 static gboolean 1498 compress_zip (const gchar *target_name, const gchar *tmpdir, 1499 FSEXAM_setting *setting) 1500 { 1501 gchar **argv = NULL; 1502 gboolean ret = FALSE; 1503 gchar *bname = NULL; 1504 gchar *tmpname = NULL; 1505 1506 bname = g_path_get_basename (target_name); 1507 tmpname = g_strdup_printf ("%s/%s", tmpdir, bname); 1508 1509 argv = g_malloc (sizeof (gchar **) * 5); 1510 argv[0] = "/usr/bin/zip"; 1511 argv[1] = "-qr"; 1512 argv[2] = tmpname; 1513 argv[3] = "."; 1514 argv[4] = NULL; 1515 1516 if (! run_cmd (argv, NULL, setting)) { 1517 goto DONE; 1518 } 1519 1520 argv[0] = "/usr/bin/cp"; 1521 argv[1] = tmpname; 1522 argv[2] = (gchar *)target_name; 1523 argv[3] = NULL; 1524 1525 if (! run_cmd (argv, NULL, setting)) 1526 goto DONE; 1527 1528 ret = TRUE; 1529 1530 DONE: 1531 g_free (argv); 1532 g_free (bname); 1533 g_free (tmpname); 1534 1535 return ret; 1536 } 1537 1538 1539 static gboolean 1540 compress_gz (const gchar *target_name, FSEXAM_setting *setting) 1541 { 1542 gchar **argv = NULL; 1543 gboolean ret = FALSE; 1544 1545 argv = g_malloc (sizeof (gchar **) * 5); 1546 argv[0] = TARCMD; 1547 argv[1] = "-czf"; 1548 argv[2] = (gchar *)target_name; 1549 argv[3] = "."; 1550 argv[4] = NULL; 1551 1552 if (! run_cmd (argv, NULL, setting)) { 1553 goto DONE; 1554 } 1555 1556 ret = TRUE; 1557 1558 DONE: 1559 g_free (argv); 1560 1561 return ret; 1562 } 1563 1564 1565 /* 1566 * Compress .bz2, .gz, .zip, .Z 1567 * dname: the directory name which will contain the result file 1568 * bname: the result filename, such as *.tar.bz2 1569 */ 1570 static gboolean 1571 fsexam_compress (const gchar *target_name, const gchar *tmpdir, 1572 Compress_Type type, FSEXAM_setting *setting) 1573 { 1574 /* uncompress */ 1575 if (type == COMP_TARGZ) { 1576 return compress_gz (target_name, setting); 1577 } else if (type == COMP_TARBZ2) { 1578 return compress_bz2 (target_name, setting); 1579 } else if (type == COMP_TAR) { 1580 return compress_tar (target_name, setting); 1581 } else if (type == COMP_ZIP) { 1582 return compress_zip (target_name, tmpdir, setting); 1583 } else if (type == COMP_Z) { 1584 return compress_Z (target_name, setting); 1585 } else { 1586 if (setting->display_msg) 1587 setting->display_msg (target_name, 1588 _("Don't support this file type")); 1589 } 1590 1591 return FALSE; 1592 } 1593 1594 /* 1595 * Description: 1596 * Unarchive/Uncompress file, execute name or content conversion, then 1597 * Rearchive/Recompress and replace the original file. 1598 * 1599 * Parameter: 1600 * fullpath: the full path of compress file, such as /tmp/a.tar 1601 * info: Path needed by compress conversion 1602 */ 1603 static gboolean 1604 compress_common_convert (const gchar *fullpath, 1605 Compress_info *info, 1606 FSEXAM_setting *setting, 1607 gboolean restore, 1608 gboolean nameconvert) 1609 { 1610 Compress_Type type; 1611 gchar oldcwd[PATH_MAX]; 1612 gchar *bname = NULL; 1613 gchar *dname = NULL; 1614 gchar *tempdir = NULL; /* temparay directory */ 1615 gchar *template = NULL; /* template for temp dir */ 1616 gchar *compress_cmd = NULL; 1617 1618 if (! fsexam_special_is_compress (fullpath, &type)) { 1619 return FALSE; 1620 } 1621 1622 /* 1623 * cd to temparary directory at the same directory 1624 * with original file and then uncompress. 1625 */ 1626 if (getcwd (oldcwd, PATH_MAX) == NULL) { 1627 fsexam_errno = ERR_GET_CWD; 1628 goto done; 1629 } 1630 1631 bname = g_path_get_basename (fullpath); 1632 dname = g_path_get_dirname (fullpath); 1633 1634 template = g_strdup_printf ("%sXXXXXX", fullpath); 1635 tempdir = mkdtemp (template); 1636 1637 if (tempdir == NULL) { 1638 if (fsexam_debug () & FSEXAM_DBG_ARCHIVE) 1639 g_print ("mkdtemp return NULL\n"); 1640 1641 fsexam_errno = ERR_NO_RIGHTS; 1642 goto done; 1643 } 1644 1645 if (fsexam_debug () & FSEXAM_DBG_ARCHIVE) 1646 g_print ("Succeed to create tempdir %s\n", tempdir); 1647 1648 if (chdir (tempdir)) { /* uncompress file into temp dir */ 1649 fsexam_errno = ERR_NO_RIGHTS; 1650 goto done; 1651 } 1652 1653 if (! fsexam_uncompress (fullpath, tempdir, type, setting)) { 1654 if (fsexam_debug () & FSEXAM_DBG_ARCHIVE) { 1655 g_print ("Error when uncompress %s to %s\n", fullpath, tempdir); 1656 } 1657 /* chdir to orig dir at error */ 1658 chdir (oldcwd); 1659 goto done; 1660 } 1661 1662 if (fsexam_debug () & FSEXAM_DBG_ARCHIVE) 1663 g_print ("Succeed to uncompress %s to %s\n", fullpath, tempdir); 1664 1665 /* 1666 * Before converting, ensure the tempdir is not empty. 1667 * If it is empty, this means that the archive file 1668 * may have absolute path, this will dangerous. Or 1669 * we met with unknow error. 1670 */ 1671 if (rmdir (tempdir) == 0) { 1672 if (fsexam_debug () & FSEXAM_DBG_ARCHIVE) { 1673 g_print ("Error: archive use absolute path or met unknow error\n"); 1674 } 1675 1676 if (setting->display_msg) 1677 setting->display_msg (NULL, 1678 _("The archive file is empty or has absolute path, so can not convert files in this archive file")); 1679 chdir (oldcwd); 1680 goto done; 1681 } 1682 1683 info->temp_dir_len = strlen (tempdir); 1684 1685 if (nameconvert) { /* name conversion */ 1686 compress_convert_filename (tempdir, /* contain unarchived files */ 1687 info, 1688 setting, 1689 restore); 1690 } else { /* content conversion */ 1691 compress_convert_content (tempdir, /* contain unarchived files */ 1692 info, 1693 setting, 1694 restore); 1695 } 1696 1697 /* recompress */ 1698 if (! fsexam_compress (fullpath, tempdir, type, setting)) { 1699 /* chdir to orig dir at error */ 1700 if (fsexam_debug () & FSEXAM_DBG_ARCHIVE) { 1701 g_print ("Error when recompress %s to %s\n", tempdir, fullpath); 1702 } 1703 } 1704 1705 if (fsexam_debug () & FSEXAM_DBG_ARCHIVE) 1706 g_print ("Succeed to recompress %s to %s\n", tempdir, fullpath); 1707 1708 chdir (oldcwd); 1709 if (! delete_files (tempdir, setting)) { 1710 if (fsexam_debug () & FSEXAM_DBG_ARCHIVE) { 1711 g_print ("Error when delete tempdir: %s\n", tempdir); 1712 } 1713 } 1714 1715 if (fsexam_debug () & FSEXAM_DBG_ARCHIVE) 1716 g_print ("Succeed to delete tempdir %s\n", tempdir); 1717 1718 done: 1719 g_free (dname); 1720 g_free (bname); 1721 g_free (template); 1722 1723 return TRUE; 1724 } 1725 1726 /* content conversion */ 1727 static gboolean 1728 fsexam_compress_convert_content (const gchar *fullpath, 1729 FSEXAM_setting *setting, 1730 gboolean restore) 1731 { 1732 Compress_info *info; 1733 gboolean ret; 1734 1735 info = compress_info_new (fullpath, NULL, NULL); 1736 1737 if (info == NULL) 1738 return FALSE; 1739 1740 ret = compress_common_convert (fullpath, /* abs path of archive file */ 1741 info, 1742 setting, 1743 restore, /* Convert or Restore */ 1744 FALSE); /* Content conversion instead of name conversion */ 1745 1746 compress_info_free (info); 1747 1748 return ret; 1749 } 1750 1751 1752 1753 1754 /* ----------- For content conversion --------------------------- */ 1755 1756 gboolean 1757 fsexam_special_is_special_for_content (const gchar *fullpath, 1758 FSEXAM_setting *setting) 1759 { 1760 return fsexam_special_is_compress (fullpath, NULL); 1761 } 1762 1763 /* 1764 * Iterate every special file handling module. This assumes that no two special 1765 * module will handle the same one file. Return True if file has been 1766 * proccessed by one special module; otherwise return False. 1767 */ 1768 gboolean 1769 fsexam_special_convert_content (const gchar *fullpath, 1770 FSEXAM_setting *setting, 1771 gboolean restore) 1772 { 1773 g_return_val_if_fail ((fullpath != NULL) && (setting != NULL), FALSE); 1774 1775 gboolean ret; 1776 1777 if (fsexam_compress_convert_content (fullpath, setting, restore)) { 1778 ret = TRUE; 1779 }else{ 1780 ret = FALSE; 1781 } 1782 1783 return ret; 1784 } 1785 1786 1787 /* ------------- For name convert ------------------- */ 1788 1789 /* 1790 * If fullpath is supported archive or compress file, then 1791 * return TRUE, otherwise return FALSE. 1792 */ 1793 gboolean 1794 fsexam_special_is_special_for_name (const gchar *fullpath, 1795 FSEXAM_setting *setting) 1796 { 1797 return fsexam_special_is_compress (fullpath, NULL); 1798 } 1799 1800 /*=================================================================== 1801 * Description: 1802 * Convert or Restore the name of special type file. 1803 * 1804 * Parameters: 1805 * setting: Contain Total setting/preference information 1806 * fullpath: Absolute path or archive or compress file, such as 1807 * /tmp/test/test.tar.gz 1808 * hist_search_path: Use the oldname(before restore) as history search 1809 * path. This is only used for restore. This can ensure path 1810 * in history is consistent with path in disk. 1811 * restore: convert name or restore name 1812 * 1813 * Return value: 1814 *=====================================================================*/ 1815 gboolean 1816 fsexam_compress_convert_name (FSEXAM_setting *setting, 1817 const gchar *fullpath, 1818 const gchar *hist_search_path, 1819 gboolean restore) 1820 { 1821 gboolean ret; 1822 Compress_info *info; 1823 gchar *search_path; 1824 1825 /* 1826 * hist_search_path is passed by caller, and it is different when 1827 * restore is performed. When restore, search_path is the direct 1828 * path used to search in history, don't need compose 1829 */ 1830 search_path = g_filename_to_uri (hist_search_path, NULL, NULL); 1831 info = compress_info_new (fullpath, search_path +URI_HEAD_LEN, fullpath); 1832 1833 if (NULL == info) { 1834 return FALSE; 1835 } 1836 1837 ret = compress_common_convert (fullpath, /* abs path of archive file */ 1838 info, 1839 setting, 1840 restore, /* Convert or Restore */ 1841 TRUE); /* Convert Name instead of content */ 1842 1843 compress_info_free (info); 1844 g_free (search_path); 1845 1846 return ret; 1847 } 1848