|
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 |
|
27 #ifdef HAVE_CONFIG_H |
|
28 #include <config.h> |
|
29 #endif |
|
30 |
|
31 #include <strings.h> |
|
32 #include <unistd.h> |
|
33 #include <string.h> |
|
34 #include <stdlib.h> |
|
35 #include <dirent.h> |
|
36 #include <libgen.h> |
|
37 #include <unistd.h> |
|
38 |
|
39 #include "fsexam-header.h" |
|
40 #include "fsexam-convcontent.h" |
|
41 |
|
42 /* Append SUFFIX when has duplicated name */ |
|
43 #define SUFFIX "utf-8" |
|
44 |
|
45 static gboolean write_to_disk (FSEXAM_setting *, |
|
46 const gchar *path, |
|
47 const gchar *origname, |
|
48 const gchar *utf8name, |
|
49 short from_encoding, |
|
50 short to_encoding, |
|
51 gchar **actualname); |
|
52 |
|
53 static gboolean real_convert (FSEXAM_setting *setting, |
|
54 const gchar *dname, |
|
55 const gchar *bname, |
|
56 gchar **newname); |
|
57 static gboolean convert_symlink_target_node ( |
|
58 GNode *node, |
|
59 FSEXAM_setting *setting, |
|
60 gboolean restore); |
|
61 static gboolean wrapped_convert_node (GNode *node, FSEXAM_setting *setting); |
|
62 static gboolean wrapped_restore_convert_node (GNode *node, gpointer data); |
|
63 static gboolean convert_node (GNode *node, gpointer data); |
|
64 static gboolean dryrun_convert_node (GNode *node, gpointer data); |
|
65 static gboolean restore_convert_node (GNode *node, gpointer data); |
|
66 static gboolean fsexam_convert_scenario_for_name (FSEXAM_setting *setting); |
|
67 static gboolean fsexam_restore_name (FSEXAM_setting *setting, GList *list); |
|
68 static gboolean _convert_directory (FSEXAM_setting *setting, const gchar *); |
|
69 static void convert_directory (FSEXAM_setting *setting, GNode *node); |
|
70 static gint construct_candidate_list (GList *list, gboolean forname); |
|
71 |
|
72 |
|
73 /* |
|
74 * Recreate symlink from file in symlink_node to file in target_node |
|
75 */ |
|
76 static gboolean |
|
77 relink_symlink (GNode *symlink_node, |
|
78 GNode *target_node, |
|
79 FSEXAM_setting *setting) |
|
80 { |
|
81 gchar *symlink_contents = NULL; |
|
82 gchar *symlink_path = NULL; |
|
83 gchar *target_path = NULL; |
|
84 gchar *log_msg = NULL; |
|
85 gboolean ret = FALSE; |
|
86 |
|
87 if ((NULL == symlink_node) || (NULL == target_node) || (NULL == setting)) |
|
88 return FALSE; |
|
89 |
|
90 symlink_path = fsexam_tree_get_path (symlink_node, FALSE); |
|
91 symlink_contents = g_file_read_link (symlink_path, NULL); |
|
92 |
|
93 if (NULL == symlink_contents) { |
|
94 fsexam_errno = ERR_CANNOT_READ; |
|
95 goto done; |
|
96 } |
|
97 |
|
98 if (remove (symlink_path) == -1) { /* delete original symlink */ |
|
99 fsexam_errno = ERR_CANNOT_RM_SYMLINK; |
|
100 goto done; |
|
101 } |
|
102 |
|
103 if (*symlink_contents == '/') { /* absolute symlink */ |
|
104 target_path = fsexam_tree_get_path (target_node, FALSE); |
|
105 }else{ |
|
106 /* reconstruct symlink path for relative symlink */ |
|
107 gchar *tmp = symlink_contents; |
|
108 gchar *cur = tmp; |
|
109 GNode *parent_node = symlink_node->parent; |
|
110 gboolean finish = FALSE; |
|
111 |
|
112 while (!finish) { |
|
113 if ((*tmp != '/') && (*tmp != '\0')) { |
|
114 tmp++; |
|
115 continue; |
|
116 }else{ /* got one subpath */ |
|
117 if (*tmp == '\0') |
|
118 finish = TRUE; |
|
119 else |
|
120 *tmp = '\0'; |
|
121 |
|
122 if (strcmp (cur, ".") == 0) { |
|
123 /* no op */ |
|
124 }else if (strcmp (cur, "..") == 0) { |
|
125 parent_node = parent_node->parent; |
|
126 }else if (strcmp (cur, "") == 0) { |
|
127 /* this means '//' in the symlink_contents */ |
|
128 cur = "/"; |
|
129 }else{ |
|
130 GNode *gnode = fsexam_tree_search_name (parent_node, cur); |
|
131 if (gnode == NULL) { /* fallback to use absolute path */ |
|
132 g_free (target_path); |
|
133 target_path = fsexam_tree_get_path (target_node, FALSE); |
|
134 |
|
135 break; |
|
136 }else{ |
|
137 TreeNode *tnode = (TreeNode *)gnode->data; |
|
138 |
|
139 if (TREENODE_IS_CONVERTED (tnode)) |
|
140 cur = TREENODE_GET_UTF8 (tnode); |
|
141 else |
|
142 cur = TREENODE_GET_ORIG (tnode); |
|
143 } |
|
144 |
|
145 parent_node = parent_node->parent; |
|
146 } |
|
147 |
|
148 if (target_path == NULL) { |
|
149 target_path = g_strdup (cur); |
|
150 }else{ |
|
151 if (strcmp (cur, "/") == 0) { |
|
152 cur = g_strdup_printf ("%s%s", target_path, cur); |
|
153 }else{ |
|
154 cur = g_strdup_printf ("%s/%s", target_path, cur); |
|
155 } |
|
156 |
|
157 g_free (target_path); |
|
158 target_path = cur; |
|
159 } |
|
160 |
|
161 cur = ++tmp; |
|
162 } |
|
163 } /* endof while */ |
|
164 } |
|
165 |
|
166 if (symlink (target_path, symlink_path) == -1) { |
|
167 fsexam_errno = ERR_LOST_SYMLINK_FILE; |
|
168 goto done; |
|
169 } |
|
170 |
|
171 ret = TRUE; |
|
172 |
|
173 done: |
|
174 if (ret) |
|
175 log_msg = _("Re-create symbolic link success"); |
|
176 |
|
177 fsexam_log_puts (setting->log_info, symlink_path, log_msg); |
|
178 if (setting->display_msg) |
|
179 setting->display_msg (symlink_path, log_msg); |
|
180 |
|
181 g_free (symlink_contents); |
|
182 g_free (target_path); |
|
183 g_free (symlink_path); |
|
184 |
|
185 return ret; |
|
186 } |
|
187 |
|
188 /*==================================================================== |
|
189 * Function Name: write_to_disk |
|
190 * |
|
191 * Parameters: |
|
192 * FSEXAM_setting *setting: |
|
193 * gchar *path: The dir name which contain file to be renamed |
|
194 * gchar *orig: The original name |
|
195 * gchar *utf8name: The utf8 name |
|
196 * gchar **actualname: the actual name used if succeed |
|
197 * |
|
198 * Desc: |
|
199 * Rename the file from orig to utf8name. If newname exists, then will |
|
200 * find one new name, and actualname point to it. |
|
201 * |
|
202 * Will handle log/history in this function, dryrun/restore |
|
203 * may call this function directly. |
|
204 * |
|
205 * Return value: |
|
206 * If rename success, then return TRUE; |
|
207 * otherwise(such as can't rename, can't write to log) return FALSE. |
|
208 * |
|
209 * Author: Yandong Yao 2006/08/31 |
|
210 ========================================================================*/ |
|
211 static gboolean |
|
212 write_to_disk (FSEXAM_setting *setting, |
|
213 const gchar *path, /* the path of current file */ |
|
214 const gchar *origname, /* old base name */ |
|
215 const gchar *utf8name, /* new base name */ |
|
216 short from_encoding, /* from encoding */ |
|
217 short to_encoding, /* to encoding */ |
|
218 gchar **actualname) /* return the actual used */ |
|
219 { |
|
220 static gchar oldname[PATH_MAX]; |
|
221 static gchar newname[PATH_MAX]; |
|
222 gchar *retname = NULL; |
|
223 gchar *fname = NULL; |
|
224 gchar *msg = NULL; |
|
225 gboolean ret = FALSE; |
|
226 |
|
227 if ((NULL == setting) || (NULL == path) || (NULL == origname) |
|
228 || (NULL == utf8name)) |
|
229 return FALSE; |
|
230 |
|
231 fsexam_errno = ERR_OK; |
|
232 |
|
233 /* construct full old name and full new name */ |
|
234 g_snprintf (oldname, PATH_MAX - 1, "%s/%s", path, origname); |
|
235 g_snprintf (newname, PATH_MAX - 1, "%s/%s", path, utf8name); |
|
236 |
|
237 /* whether newname == oldname? */ |
|
238 if (strcmp (utf8name, origname) == 0) { |
|
239 fsexam_errno = ERR_NAME_SAME; |
|
240 goto done; |
|
241 } |
|
242 |
|
243 if (g_file_test (newname, G_FILE_TEST_EXISTS)) { |
|
244 fsexam_errno = ERR_NAME_EXIST; |
|
245 fname = find_non_exist_name (newname); |
|
246 |
|
247 if (fname == NULL) { |
|
248 fsexam_errno = ERR_CANNOT_RENAME; |
|
249 }else if (rename(oldname, fname) == 0){ |
|
250 retname = g_strdup (basename (fname)); |
|
251 ret = TRUE; |
|
252 }else{ |
|
253 fsexam_errno = ERR_CANNOT_RENAME; |
|
254 } |
|
255 }else{ |
|
256 if (rename(oldname, newname) == 0){ |
|
257 retname = g_strdup (utf8name); |
|
258 ret = TRUE; |
|
259 }else{ |
|
260 fsexam_errno = ERR_CANNOT_RENAME; /* inc dup name */ |
|
261 } |
|
262 } |
|
263 |
|
264 if (ret) { |
|
265 if (! (setting->flags & FSEXAM_SETTING_FLAGS_UNDO)) { |
|
266 gboolean same_serial = TRUE; |
|
267 |
|
268 if (setting->flags & FSEXAM_SETTING_FLAGS_DIFF_SERIAL) { |
|
269 setting->flags &= ~FSEXAM_SETTING_FLAGS_DIFF_SERIAL; |
|
270 same_serial = FALSE; |
|
271 } |
|
272 |
|
273 fsexam_history_put (setting->hist_info, |
|
274 ConvName, |
|
275 newname, |
|
276 from_encoding, |
|
277 to_encoding, |
|
278 same_serial); |
|
279 } |
|
280 |
|
281 if (setting->update_gui) { |
|
282 setting->update_gui (setting, path, origname, retname); |
|
283 } |
|
284 |
|
285 ++setting->succ_num; |
|
286 } else { |
|
287 ++setting->fail_num; |
|
288 } |
|
289 |
|
290 done: |
|
291 msg = g_strdup_printf (_("[Name] %s -> %s"), |
|
292 id2encoding (from_encoding), |
|
293 id2encoding (to_encoding)); |
|
294 |
|
295 /* Display messages to user */ |
|
296 if (setting->display_msg) { |
|
297 if (ret) |
|
298 setting->display_msg (newname, msg); |
|
299 else |
|
300 setting->display_msg (oldname, fsexam_error_get_msg ()); |
|
301 } |
|
302 |
|
303 /* Writting log */ |
|
304 if (fsexam_errno == ERR_OK) { |
|
305 fsexam_log_puts (setting->log_info, newname, msg); |
|
306 }else if (fsexam_errno == ERR_NAME_EXIST) { |
|
307 fsexam_log_puts (setting->log_info, fname, NULL); |
|
308 }else{ |
|
309 fsexam_log_puts (setting->log_info, newname, NULL); |
|
310 } |
|
311 |
|
312 if (actualname != NULL) |
|
313 *actualname = retname; //freed outside |
|
314 else |
|
315 g_free (retname); |
|
316 |
|
317 g_free (msg); |
|
318 g_free (fname); |
|
319 |
|
320 return ret; |
|
321 } |
|
322 |
|
323 /*==================================================================== |
|
324 * Function Name: real_convert |
|
325 * |
|
326 * Parameters: |
|
327 * FSEXAM_setting *setting: |
|
328 * const gchar *dname: the directory in which file reside |
|
329 * const gchar *bname: the filename without any directory name |
|
330 * gchar **newname: return the new name when success. Need free by caller |
|
331 * |
|
332 * Desc: |
|
333 * real_convert() will convert the filename using provided encoding list, |
|
334 * and display candidates to user in interactive mode. |
|
335 * |
|
336 * If success to rename file on the disk, then newname will contain the |
|
337 * new name. |
|
338 * |
|
339 * This function will handle log information also. |
|
340 * |
|
341 * write_to_disk() will handle log either, because it can be call by |
|
342 * other funcs. |
|
343 * |
|
344 * Return value: |
|
345 * If succeed to rename the file, return TRUE, otherwise return FALSE. |
|
346 * In dryrun mode, always return FALSE. |
|
347 * |
|
348 * The most important usage for the return value is to determine whether |
|
349 * fsexam change the real file name on disk or not. |
|
350 * |
|
351 * Author: Yandong Yao 2006/09/01 |
|
352 ========================================================================*/ |
|
353 static gboolean |
|
354 real_convert (FSEXAM_setting *setting, |
|
355 const gchar *dname, |
|
356 const gchar *bname, |
|
357 gchar **newname) |
|
358 { |
|
359 Score score; |
|
360 gchar *fullname = NULL; |
|
361 gboolean ret = FALSE; |
|
362 |
|
363 if ((NULL == setting) || (NULL == dname) || (NULL ==bname)) |
|
364 return FALSE; |
|
365 |
|
366 fsexam_errno = ERR_OK; |
|
367 |
|
368 fullname = g_strdup_printf ("%s/%s", dname, bname); |
|
369 |
|
370 if (setting->pref->auto_detect) { /* handle encoding auto detection */ |
|
371 GList *detected_encoding; |
|
372 |
|
373 detected_encoding = str_encoding_detect (bname, DEFAULT_DETECTING_FLAG); |
|
374 setting->pref->encode_list = fsexam_encoding_add_auto ( |
|
375 setting->pref->encode_list, |
|
376 detected_encoding); |
|
377 auto_encoding_free (detected_encoding); |
|
378 } |
|
379 |
|
380 score = fsexam_encoding_decode (setting->pref->encode_list, |
|
381 ConvName, |
|
382 (gchar *)bname, |
|
383 strlen(bname), |
|
384 setting->pref->force); |
|
385 |
|
386 |
|
387 if (setting->pref->dry_run){ /* dry run */ |
|
388 ret = fsexam_dryrun_puts (setting->dryrun_info, |
|
389 fullname, |
|
390 score, |
|
391 setting->pref->encode_list, |
|
392 ConvName); |
|
393 ret ? ++setting->succ_num : ++setting->fail_num; |
|
394 } else { /* real convert */ |
|
395 gint index = 0; |
|
396 gchar *actualname = NULL; |
|
397 Encoding *encoding = NULL; |
|
398 |
|
399 if ((score == FAIL) || (score == ORIGINAL)){ |
|
400 fsexam_errno = (score == FAIL) ? ERR_NO_PROPER_ENCODING |
|
401 : ERR_NAME_UTF8_ALREADY; |
|
402 fsexam_log_puts_folder_and_name (setting->log_info, |
|
403 dname, bname, |
|
404 NULL); |
|
405 if (setting->display_msg) |
|
406 setting->display_msg (fullname, fsexam_error_get_msg()); |
|
407 |
|
408 goto done; |
|
409 } |
|
410 |
|
411 /* |
|
412 * User may select don't ask me again |
|
413 */ |
|
414 if (setting->gold_index != -1) { |
|
415 index = setting->gold_index; |
|
416 } else if (setting->pref->auto_conversion) { |
|
417 index = fsexam_encoding_get_first_index ( |
|
418 setting->pref->encode_list); |
|
419 } else { |
|
420 index = setting->get_index (setting->pref->encode_list, TRUE); |
|
421 } |
|
422 |
|
423 if (index == -1) { /* cancel the selection */ |
|
424 fsexam_errno = ERR_CANCEL_CONVERSION; |
|
425 goto done; |
|
426 } |
|
427 |
|
428 encoding = (Encoding *)g_list_nth_data (setting->pref->encode_list, |
|
429 index); |
|
430 if (NULL == encoding){ |
|
431 fsexam_errno = ERR_ENCODING_INDEX_INVALID; |
|
432 fsexam_log_puts_folder_and_name (setting->log_info, |
|
433 dname, bname, |
|
434 NULL); |
|
435 if (setting->display_msg) |
|
436 setting->display_msg (fullname, fsexam_error_get_msg()); |
|
437 |
|
438 goto done; |
|
439 } |
|
440 |
|
441 ret = write_to_disk (setting, |
|
442 dname, |
|
443 bname, |
|
444 encoding->u.converted_text, |
|
445 encoding->encodingID, |
|
446 encoding2id ("UTF-8"), |
|
447 &actualname); |
|
448 |
|
449 if ((ret) && (newname)) { // Return new name |
|
450 *newname = actualname; |
|
451 }else{ |
|
452 g_free (actualname); |
|
453 } |
|
454 } |
|
455 |
|
456 done: |
|
457 if (setting->pref->auto_detect) |
|
458 setting->pref->encode_list = fsexam_encoding_remove_auto ( |
|
459 setting->pref->encode_list); |
|
460 |
|
461 g_free (fullname); |
|
462 |
|
463 return ret; |
|
464 } |
|
465 |
|
466 /* |
|
467 * convert one directory recursively. won't care about symlink |
|
468 */ |
|
469 static gboolean |
|
470 common_convert_directory (FSEXAM_setting *setting, |
|
471 const gchar *dname, |
|
472 gboolean restore) |
|
473 { |
|
474 struct stat statbuf; |
|
475 struct dirent *dirp = NULL; |
|
476 DIR *dp = NULL; |
|
477 gchar *childname = NULL; |
|
478 gboolean ret = FALSE; |
|
479 |
|
480 if ((NULL == dname) || (NULL == setting)) |
|
481 return FALSE; |
|
482 |
|
483 if ((dp = opendir (dname)) == NULL){ |
|
484 fsexam_errno = ERR_CANNOT_OPEN; |
|
485 fsexam_log_puts (setting->log_info, dname, NULL); |
|
486 if (setting->display_msg) |
|
487 setting->display_msg (dname, fsexam_error_get_msg()); |
|
488 |
|
489 return ret; |
|
490 } |
|
491 |
|
492 while ((dirp = readdir (dp)) != NULL){ |
|
493 if ((strcmp (dirp->d_name, ".") == 0) |
|
494 || (strcmp (dirp->d_name, "..") == 0)) |
|
495 continue; |
|
496 |
|
497 fsexam_errno = ERR_OK; |
|
498 |
|
499 childname = g_strdup_printf ("%s/%s", dname, dirp->d_name); |
|
500 |
|
501 /* need convert this filename or not? */ |
|
502 if (lstat (childname, &statbuf) == -1) |
|
503 fsexam_errno = ERR_FILE_NONEXIST; |
|
504 else if (!(S_ISREG(statbuf.st_mode)) |
|
505 && !(S_ISDIR(statbuf.st_mode)) && !(S_ISLNK(statbuf.st_mode))){ |
|
506 fsexam_errno = ERR_FILE_TYPE_NOT_SUPPORT; |
|
507 }else if ((! setting->pref->hidden) && (*(dirp->d_name) == '.')){ |
|
508 fsexam_errno = ERR_IGNORE_HIDDEN_FILE; |
|
509 }else if ((!setting->pref->remote) |
|
510 && (is_remote_file (setting->remote_path, childname))) { |
|
511 fsexam_errno = ERR_IGNORE_REMOTE_FILE; |
|
512 } |
|
513 |
|
514 if (fsexam_errno != ERR_OK) { |
|
515 fsexam_log_puts (setting->log_info, childname, NULL); |
|
516 if (setting->display_msg) |
|
517 setting->display_msg (childname, fsexam_error_get_msg()); |
|
518 g_free (childname); |
|
519 continue; |
|
520 } |
|
521 |
|
522 if ((!setting->pref->force) |
|
523 && (str_isutf8 (dirp->d_name, DEFAULT_DETECTING_FLAG))) { |
|
524 fsexam_errno = ERR_NAME_UTF8_ALREADY; |
|
525 } |
|
526 |
|
527 if (restore) { |
|
528 //Currently tree for restore name has no -R node, so no-op |
|
529 }else if (fsexam_errno != ERR_NAME_UTF8_ALREADY) { |
|
530 gchar *newname = NULL; |
|
531 |
|
532 ret = real_convert (setting, dname, dirp->d_name, &newname); |
|
533 |
|
534 if (ret && newname != NULL){ |
|
535 g_free (childname); |
|
536 childname = g_strdup_printf ("%s/%s", dname, newname); |
|
537 lstat(childname, &statbuf); |
|
538 } |
|
539 |
|
540 g_free (newname); |
|
541 } |
|
542 |
|
543 if (setting->flags & FSEXAM_SETTING_FLAGS_STOP) { |
|
544 g_free (childname); |
|
545 goto done; |
|
546 } |
|
547 |
|
548 if (! setting->pref->dry_run |
|
549 && setting->pref->special |
|
550 && fsexam_special_is_special_for_name (childname, setting)) { |
|
551 gchar *hist_search_path; |
|
552 |
|
553 /* history search path is for search Hist_item in history file */ |
|
554 hist_search_path = g_strdup_printf ("%s/%s", dname, dirp->d_name); |
|
555 fsexam_compress_convert_name (setting, |
|
556 childname, |
|
557 hist_search_path, |
|
558 restore); |
|
559 g_free (hist_search_path); |
|
560 } else if (S_ISDIR(statbuf.st_mode)) { |
|
561 _convert_directory(setting, childname); |
|
562 } |
|
563 |
|
564 g_free (childname); |
|
565 } |
|
566 |
|
567 done: |
|
568 closedir (dp); |
|
569 |
|
570 return ret; |
|
571 } |
|
572 |
|
573 static gboolean |
|
574 _convert_directory (FSEXAM_setting *setting, const gchar *dname) |
|
575 { |
|
576 return common_convert_directory (setting, dname, FALSE); |
|
577 } |
|
578 |
|
579 /* |
|
580 static gboolean |
|
581 _restore_directory (FSEXAM_setting *setting, const gchar *dname) |
|
582 { |
|
583 return common_convert_directory (setting, dname, TRUE); |
|
584 } |
|
585 */ |
|
586 |
|
587 /* |
|
588 * convert to fullpath, then call _convert_directory |
|
589 */ |
|
590 static void |
|
591 convert_directory (FSEXAM_setting *setting, GNode *node) |
|
592 { |
|
593 gchar *dir = fsexam_tree_get_path (node, FALSE); |
|
594 |
|
595 _convert_directory (setting, dir); |
|
596 |
|
597 return; |
|
598 } |
|
599 |
|
600 /* |
|
601 * Convert the symlink target, and convert parent first if has not do. |
|
602 */ |
|
603 static gboolean |
|
604 convert_symlink_target_node (GNode *node, |
|
605 FSEXAM_setting *setting, |
|
606 gboolean restore) |
|
607 { |
|
608 TreeNode *tnode = NULL; |
|
609 |
|
610 if ((NULL == node) || (NULL == setting)) |
|
611 return FALSE; |
|
612 |
|
613 tnode = (TreeNode *)node->data; |
|
614 |
|
615 if (TREENODE_IS_TRAVERSED (tnode)) { |
|
616 return TREENODE_IS_CONVERTED (tnode) ? TRUE : FALSE; |
|
617 } |
|
618 |
|
619 if (setting->flags & FSEXAM_SETTING_FLAGS_STOP) |
|
620 return FALSE; /* stop the recursive */ |
|
621 |
|
622 if ((node->parent != NULL) |
|
623 && (! TREENODE_IS_TRAVERSED ((TreeNode *)((node->parent)->data)))) { |
|
624 convert_symlink_target_node (node->parent, setting, restore); |
|
625 } |
|
626 |
|
627 if (setting->flags & FSEXAM_SETTING_FLAGS_STOP) |
|
628 return FALSE; /* stop the recursive */ |
|
629 |
|
630 if (restore) |
|
631 return wrapped_restore_convert_node (node, (gpointer)setting); |
|
632 else |
|
633 return wrapped_convert_node (node, (gpointer)setting); |
|
634 } |
|
635 |
|
636 /*============================================================================ |
|
637 * Function Name: convert_node |
|
638 * |
|
639 * Parameters: |
|
640 * FSEXAM_setting *: contain preference information |
|
641 * GNode *node: The node which will be handled |
|
642 * |
|
643 * Desc: |
|
644 * GNode Traverse function. Convert one node in the whole tree. |
|
645 * Need care about recursive flag |
|
646 * |
|
647 * Because this function will called by g_node_traverse, so we need |
|
648 * handle various error information here. |
|
649 * |
|
650 * Return value: |
|
651 * Return TRUE to stop g_node_traverse(). |
|
652 * |
|
653 * Author: |
|
654 * Yandong Yao 2006/08/22 |
|
655 ============================================================================*/ |
|
656 static gboolean |
|
657 convert_node (GNode *node, gpointer data) |
|
658 { |
|
659 FSEXAM_setting *setting = (FSEXAM_setting *)data; |
|
660 |
|
661 wrapped_convert_node (node, setting); |
|
662 |
|
663 if (setting->flags & FSEXAM_SETTING_FLAGS_STOP) |
|
664 return TRUE; |
|
665 |
|
666 return FALSE; |
|
667 } |
|
668 |
|
669 /* |
|
670 * Return TRUE if current node has been converted. |
|
671 */ |
|
672 static gboolean |
|
673 wrapped_convert_node (GNode *node, FSEXAM_setting *setting) |
|
674 { |
|
675 TreeNode *tnode = node->data; |
|
676 gboolean node_converted = FALSE; |
|
677 gchar *fullpath = NULL; |
|
678 |
|
679 if ((NULL == setting) || (NULL == tnode) |
|
680 || (TREENODE_IS_TRAVERSED (tnode))){ |
|
681 return FALSE; |
|
682 } |
|
683 |
|
684 TREENODE_SET_TRAVERSED (tnode, 1); /* avoid infinite loop for symlink */ |
|
685 |
|
686 fsexam_errno = ERR_OK; |
|
687 |
|
688 /* get stored error during tree construction */ |
|
689 if (TREENODE_FLAG_REMOTE_FILE (tnode)) { |
|
690 fsexam_errno = ERR_IGNORE_REMOTE_FILE; |
|
691 }else if (TREENODE_FLAG_HIDDEN_FILE (tnode)) { |
|
692 fsexam_errno = ERR_IGNORE_HIDDEN_FILE; |
|
693 }else if (TREENODE_FLAG_UTF8_ALREADY (tnode)) { |
|
694 fsexam_errno = ERR_NAME_UTF8_ALREADY; |
|
695 } |
|
696 |
|
697 if (fsexam_errno != ERR_OK) { |
|
698 fullpath = fsexam_tree_get_path (node, FALSE); |
|
699 fsexam_log_puts (setting->log_info, fullpath, NULL); |
|
700 if (setting->display_msg) { |
|
701 setting->display_msg (fullpath, fsexam_error_get_msg ()); |
|
702 } |
|
703 |
|
704 if (fsexam_errno != ERR_NAME_UTF8_ALREADY) |
|
705 goto done; |
|
706 } |
|
707 |
|
708 if (TREENODE_IS_NEED_CONVERT (tnode)) { |
|
709 gchar *dir = fsexam_tree_get_path (node->parent, FALSE); |
|
710 gchar *bname = tnode->orig; |
|
711 gchar *newname = NULL; |
|
712 |
|
713 node_converted = real_convert (setting, dir, bname, &newname); |
|
714 |
|
715 if (node_converted && newname != NULL) { |
|
716 TREENODE_SET_CONVERTED (tnode, 1); |
|
717 TREENODE_SET_UTF8 (tnode, newname); |
|
718 } |
|
719 g_free (fullpath); |
|
720 fullpath = g_strdup_printf ("%s/%s", dir, newname ? newname : bname); |
|
721 |
|
722 g_free (dir); |
|
723 |
|
724 if (setting->flags & FSEXAM_SETTING_FLAGS_STOP) |
|
725 goto done; |
|
726 } |
|
727 |
|
728 if (TREENODE_IS_SPECIAL (tnode)) { |
|
729 if (fullpath == NULL) |
|
730 fullpath = fsexam_tree_get_path (node, FALSE); |
|
731 |
|
732 /* |
|
733 * archive or compress filename may be converted already, |
|
734 * so get the original name. |
|
735 */ |
|
736 gchar *hist_search_path = fsexam_tree_get_path (node, TRUE); |
|
737 |
|
738 fsexam_compress_convert_name (setting, |
|
739 fullpath, |
|
740 hist_search_path, |
|
741 FALSE); |
|
742 |
|
743 g_free (hist_search_path); |
|
744 }else if (TREENODE_IS_SYMLINK (tnode)) { |
|
745 if (TREENODE_FLAG_TARGET_NOTEXIST (tnode)) { |
|
746 if (fullpath == NULL) |
|
747 fullpath = fsexam_tree_get_path (node, FALSE); |
|
748 |
|
749 fsexam_errno = ERR_SYMLINK_TARGET_NOEXIST; |
|
750 fsexam_log_puts (setting->log_info, fullpath, NULL); |
|
751 if (setting->display_msg) { |
|
752 setting->display_msg (fullpath, fsexam_error_get_msg ()); |
|
753 } |
|
754 }else if (!setting->pref->no_check_symlink_content) { |
|
755 /* follow has been handled during tree construction */ |
|
756 GNode *gnode = TREENODE_GET_TARGET (tnode); |
|
757 |
|
758 if ((gnode != NULL) && (gnode->data != NULL)) |
|
759 if (convert_symlink_target_node (gnode, setting, FALSE)) |
|
760 relink_symlink (node, gnode, setting); |
|
761 } |
|
762 } else if ((setting->pref->recursive && TREENODE_IS_RECURSIVE (tnode)) |
|
763 && (!setting->pref->follow) |
|
764 && setting->pref->no_check_symlink_content){ |
|
765 convert_directory (setting, node); |
|
766 } |
|
767 |
|
768 done: |
|
769 g_free (fullpath); |
|
770 |
|
771 return node_converted; |
|
772 } |
|
773 |
|
774 /*==================================================================== |
|
775 * Function Name: dryrun_convert_node |
|
776 * |
|
777 * Parameters: |
|
778 * GNode *node: one node created from dryrun result file. |
|
779 * gpointer data: is FSEXAM_setting passed from g_node_traverse. |
|
780 * |
|
781 * Desc: |
|
782 * Convert one node come from dryrun result file. |
|
783 * |
|
784 * We need handle various error here. |
|
785 * |
|
786 * Return value: |
|
787 * Always return TRUE, otherwise g_node_traverse will stop. |
|
788 * |
|
789 * Exception: |
|
790 * |
|
791 * Author: Yandong Yao 2006/09/05 |
|
792 ========================================================================*/ |
|
793 static gboolean |
|
794 dryrun_convert_node (GNode *node, gpointer data) |
|
795 { |
|
796 FSEXAM_setting *setting = (FSEXAM_setting *)data; |
|
797 TreeNode *tnode = node->data; |
|
798 gchar *path = NULL; |
|
799 gboolean ret; |
|
800 |
|
801 if ((NULL == setting) |
|
802 || (NULL == tnode) |
|
803 || TREENODE_IS_TRAVERSED (tnode) |
|
804 || (TREENODE_GET_UTF8 (tnode) == NULL) |
|
805 || (! TREENODE_IS_NEED_CONVERT (tnode))) { /* Ingore symlink */ |
|
806 return FALSE; |
|
807 } |
|
808 |
|
809 TREENODE_SET_TRAVERSED (tnode, 1); |
|
810 |
|
811 path = fsexam_tree_get_path (node->parent, FALSE); /* get real path */ |
|
812 |
|
813 ret = write_to_disk (setting, |
|
814 path, |
|
815 TREENODE_GET_ORIG (tnode), |
|
816 TREENODE_GET_UTF8 (tnode), |
|
817 TREENODE_GET_ID (tnode), /* from encoding */ |
|
818 encoding2id ("UTF-8"), /* to encoding */ |
|
819 NULL); |
|
820 |
|
821 /* update TreeNode */ |
|
822 if (ret) { |
|
823 TREENODE_SET_CONVERTED (tnode, 1); |
|
824 } |
|
825 |
|
826 g_free (path); |
|
827 |
|
828 return FALSE; |
|
829 } |
|
830 |
|
831 /*==================================================================== |
|
832 * Function Name: restore_convert_node |
|
833 * |
|
834 * Parameters: |
|
835 * GNode *node: node need restore |
|
836 * gpointer data: is FSEXAM_setting passed from g_node_traverse. |
|
837 * |
|
838 * Desc: |
|
839 * restore one node come from history file |
|
840 * We need handle various error here. |
|
841 * |
|
842 * Return value: |
|
843 * Always return FALSE, otherwise g_node_traverse will stop. |
|
844 * |
|
845 * Author: Yandong Yao 2006/11/27 |
|
846 ========================================================================*/ |
|
847 static gboolean |
|
848 restore_convert_node (GNode *node, gpointer data) |
|
849 { |
|
850 wrapped_restore_convert_node (node, data); |
|
851 |
|
852 return FALSE; |
|
853 } |
|
854 |
|
855 /* |
|
856 * Return TRUE if node has been converted. |
|
857 */ |
|
858 static gboolean |
|
859 wrapped_restore_convert_node (GNode *node, gpointer data) |
|
860 { |
|
861 FSEXAM_setting *setting = (FSEXAM_setting *)data; |
|
862 TreeNode *tnode = (node->data); |
|
863 gboolean node_converted = FALSE; |
|
864 gchar *dirpath = NULL; |
|
865 gchar *fullpath = NULL; |
|
866 |
|
867 if ((NULL == setting) || (NULL == tnode) |
|
868 || TREENODE_IS_TRAVERSED (tnode)) { |
|
869 return FALSE; |
|
870 } |
|
871 |
|
872 TREENODE_SET_TRAVERSED (tnode, 1); |
|
873 |
|
874 dirpath = fsexam_tree_get_path (node->parent, FALSE); |
|
875 fullpath = fsexam_tree_get_path (node, FALSE); |
|
876 |
|
877 if (dirpath == NULL) { |
|
878 g_free (fullpath); |
|
879 return FALSE; |
|
880 } |
|
881 |
|
882 fsexam_errno = ERR_OK; |
|
883 |
|
884 /* do we need convert it? */ |
|
885 if (TREENODE_FLAG_REMOTE_FILE (tnode)) { |
|
886 fsexam_errno = ERR_IGNORE_REMOTE_FILE; |
|
887 }else if (TREENODE_FLAG_HIDDEN_FILE (tnode)) { |
|
888 fsexam_errno = ERR_IGNORE_HIDDEN_FILE; |
|
889 } |
|
890 |
|
891 if (fsexam_errno != ERR_OK) { |
|
892 fsexam_log_puts (setting->log_info, fullpath, NULL); |
|
893 if (setting->display_msg) { |
|
894 setting->display_msg (fullpath, fsexam_error_get_msg ()); |
|
895 } |
|
896 |
|
897 goto done; |
|
898 } |
|
899 |
|
900 if (TREENODE_GET_ORIG (tnode) != NULL && TREENODE_GET_UTF8 (tnode) != NULL){ |
|
901 if (TREENODE_IS_REVERSE (tnode)) { |
|
902 node_converted = write_to_disk (setting, |
|
903 dirpath, |
|
904 TREENODE_GET_ORIG (tnode), |
|
905 TREENODE_GET_UTF8 (tnode), |
|
906 encoding2id ("UTF-8"), |
|
907 TREENODE_GET_ID (tnode), |
|
908 NULL); |
|
909 |
|
910 }else{ |
|
911 node_converted = write_to_disk (setting, |
|
912 dirpath, |
|
913 TREENODE_GET_ORIG (tnode), |
|
914 TREENODE_GET_UTF8 (tnode), |
|
915 TREENODE_GET_ID (tnode), |
|
916 encoding2id ("UTF-8"), |
|
917 NULL); |
|
918 } |
|
919 |
|
920 if (node_converted) |
|
921 TREENODE_SET_CONVERTED (tnode, 1); |
|
922 |
|
923 g_free (fullpath); |
|
924 fullpath = fsexam_tree_get_path (node, FALSE); |
|
925 } |
|
926 |
|
927 if (TREENODE_IS_SPECIAL (tnode)) { |
|
928 /* hist_search_path use the original name of special file */ |
|
929 gchar *hist_search_path = fsexam_tree_get_path (node, TRUE); |
|
930 |
|
931 /* Restore special type file name */ |
|
932 fsexam_compress_convert_name (setting, |
|
933 fullpath, |
|
934 hist_search_path, |
|
935 TRUE); |
|
936 |
|
937 g_free (hist_search_path); |
|
938 }else if (TREENODE_IS_SYMLINK (tnode)) { |
|
939 if (TREENODE_FLAG_TARGET_NOTEXIST (tnode)) { |
|
940 fsexam_errno = ERR_SYMLINK_TARGET_NOEXIST; |
|
941 fsexam_log_puts (setting->log_info, fullpath, NULL); |
|
942 if (setting->display_msg) { |
|
943 setting->display_msg (fullpath, fsexam_error_get_msg ()); |
|
944 } |
|
945 }else if (!setting->pref->no_check_symlink_content) { |
|
946 GNode *gnode = TREENODE_GET_TARGET (tnode); |
|
947 |
|
948 if ((gnode != NULL) && (gnode->data != NULL)) |
|
949 if (convert_symlink_target_node (gnode, setting, TRUE)) |
|
950 relink_symlink (node, gnode, setting); |
|
951 } |
|
952 } |
|
953 |
|
954 done: |
|
955 g_free (fullpath); |
|
956 g_free (dirpath); |
|
957 |
|
958 return node_converted; |
|
959 } |
|
960 |
|
961 /* |
|
962 * Display candidate list for CLI. |
|
963 * Return the total number of candidates. |
|
964 */ |
|
965 static gint |
|
966 construct_candidate_list (GList *list, gboolean forname) |
|
967 { |
|
968 gint num_candidate = 0; |
|
969 |
|
970 if (list == NULL) |
|
971 return -1; |
|
972 |
|
973 fprintf (stdout, _("Candidate list:\n")); |
|
974 fprintf (stdout, _("\t[No.] Encoding name\tConversion Result\n")); |
|
975 |
|
976 while (list != NULL) { |
|
977 Encoding *encode = (Encoding *)list->data; |
|
978 |
|
979 list = g_list_next (list); |
|
980 |
|
981 if (encode->score == FAIL) |
|
982 continue; |
|
983 |
|
984 if (forname) |
|
985 fprintf (stdout, "\t[%i] %s\t\t%s\n", |
|
986 num_candidate, |
|
987 id2encoding (encode->encodingID), |
|
988 encode->u.converted_text); |
|
989 else { /* content */ |
|
990 fprintf (stdout, "\t[%i] %s\t\t%s\n", |
|
991 num_candidate, |
|
992 id2encoding (encode->encodingID), |
|
993 encode->u.contents); |
|
994 } |
|
995 |
|
996 num_candidate++; |
|
997 } |
|
998 |
|
999 return num_candidate; |
|
1000 } |
|
1001 |
|
1002 static gboolean |
|
1003 fsexam_convert_scenario_for_name (FSEXAM_setting *setting) |
|
1004 { |
|
1005 g_return_val_if_fail (setting != NULL, FALSE); |
|
1006 |
|
1007 GSList *slist = NULL; |
|
1008 GNode *root = NULL; |
|
1009 gboolean ret; |
|
1010 |
|
1011 ret = fsexam_dryrun_process (setting->dryrun_info, &slist); |
|
1012 |
|
1013 if ((! ret) || (NULL == slist)) { |
|
1014 fsexam_log_puts (setting->log_info, NULL, NULL); |
|
1015 if (setting->display_msg) |
|
1016 setting->display_msg (NULL, fsexam_error_get_msg ()); |
|
1017 |
|
1018 setting->display_stats (setting); /* display statastics */ |
|
1019 fsexam_log_flush (setting->log_info); |
|
1020 return FALSE; |
|
1021 } |
|
1022 |
|
1023 root = fsexam_tree_construct_from_dryrun (slist, setting); |
|
1024 fsexam_dryrun_item_slist_free (slist); |
|
1025 |
|
1026 if (root == NULL) { |
|
1027 fsexam_errno = ERR_TREE_IS_EMPTY; |
|
1028 fsexam_log_puts (setting->log_info, NULL, NULL); |
|
1029 if (setting->display_msg) |
|
1030 setting->display_msg (NULL, fsexam_error_get_msg ()); |
|
1031 |
|
1032 return FALSE; |
|
1033 } |
|
1034 |
|
1035 if (fsexam_debug () |
|
1036 & (FSEXAM_DBG_OPTION | FSEXAM_DBG_TREE | FSEXAM_DBG_FILELIST)) { |
|
1037 return TRUE; |
|
1038 } |
|
1039 |
|
1040 setting->flags |= FSEXAM_SETTING_FLAGS_DIFF_SERIAL; |
|
1041 |
|
1042 g_node_traverse (root, |
|
1043 G_PRE_ORDER, |
|
1044 G_TRAVERSE_ALL, |
|
1045 -1, |
|
1046 dryrun_convert_node, |
|
1047 setting); |
|
1048 |
|
1049 setting->display_stats (setting); /* display statastics */ |
|
1050 fsexam_log_flush (setting->log_info); |
|
1051 setting->flags = 0; |
|
1052 fsexam_tree_destroy (root); |
|
1053 |
|
1054 return TRUE; |
|
1055 |
|
1056 } |
|
1057 |
|
1058 static gboolean |
|
1059 fsexam_restore_name (FSEXAM_setting *setting, GList *list) |
|
1060 { |
|
1061 g_return_val_if_fail (setting != NULL, FALSE); |
|
1062 |
|
1063 GNode *root = NULL; |
|
1064 |
|
1065 root = fsexam_tree_construct_from_history (list, |
|
1066 setting->hist_info, |
|
1067 setting); |
|
1068 |
|
1069 if ((list == NULL) || (root == NULL)){ |
|
1070 fsexam_errno = ERR_TREE_IS_EMPTY; |
|
1071 fsexam_log_puts (setting->log_info, NULL, NULL); |
|
1072 if (setting->display_msg) |
|
1073 setting->display_msg (NULL, fsexam_error_get_msg ()); |
|
1074 |
|
1075 return FALSE; |
|
1076 } |
|
1077 |
|
1078 setting->flags |= FSEXAM_SETTING_FLAGS_DIFF_SERIAL; |
|
1079 |
|
1080 if (fsexam_debug () |
|
1081 & (FSEXAM_DBG_OPTION | FSEXAM_DBG_TREE | FSEXAM_DBG_FILELIST)) { |
|
1082 return TRUE; |
|
1083 } |
|
1084 |
|
1085 g_node_traverse (root, |
|
1086 G_PRE_ORDER, |
|
1087 G_TRAVERSE_ALL, |
|
1088 -1, |
|
1089 restore_convert_node, |
|
1090 setting); |
|
1091 |
|
1092 setting->display_stats (setting); /* display statastics */ |
|
1093 fsexam_log_flush (setting->log_info); |
|
1094 setting->flags = 0; |
|
1095 fsexam_tree_destroy (root); |
|
1096 |
|
1097 return TRUE; |
|
1098 } |
|
1099 |
|
1100 /* -------------- Public API ------------------------ */ |
|
1101 |
|
1102 /* |
|
1103 * find one non exist name through append suffix. |
|
1104 * need free by caller |
|
1105 */ |
|
1106 gchar * |
|
1107 find_non_exist_name (const gchar *name) |
|
1108 { |
|
1109 gchar tmp[PATH_MAX]; |
|
1110 gint i; |
|
1111 |
|
1112 for (i = 0; ; i++) { |
|
1113 if (i) { |
|
1114 g_snprintf (tmp, PATH_MAX - 1, "%s.%s.%d", name, SUFFIX, i); |
|
1115 }else{ |
|
1116 g_snprintf (tmp, PATH_MAX - 1, "%s.%s", name, SUFFIX); |
|
1117 } |
|
1118 |
|
1119 if (! g_file_test (tmp, G_FILE_TEST_EXISTS)) |
|
1120 return g_strdup (tmp); |
|
1121 } |
|
1122 } |
|
1123 |
|
1124 /* |
|
1125 * Convert single file's fullpath, don't care any flags |
|
1126 */ |
|
1127 gboolean |
|
1128 fsexam_convert_single_filename (FSEXAM_setting *setting, |
|
1129 const gchar *filename, |
|
1130 gchar **result_name) |
|
1131 { |
|
1132 GNode *root = NULL; |
|
1133 GNode *tmp = NULL; |
|
1134 gboolean node_converted = FALSE; |
|
1135 |
|
1136 if ((filename == NULL) || (setting == NULL)) { |
|
1137 return FALSE; |
|
1138 } |
|
1139 |
|
1140 fsexam_setting_reset_stats (setting); |
|
1141 |
|
1142 if ((root = fsexam_tree_construct_from_single_file (filename)) == NULL) { |
|
1143 fsexam_errno = ERR_TREE_IS_EMPTY; |
|
1144 fsexam_log_puts (setting->log_info, NULL, NULL); |
|
1145 if (setting->display_msg) |
|
1146 setting->display_msg (NULL, fsexam_error_get_msg ()); |
|
1147 |
|
1148 return FALSE; |
|
1149 } |
|
1150 |
|
1151 setting->flags |= FSEXAM_SETTING_FLAGS_DIFF_SERIAL; |
|
1152 |
|
1153 tmp = root; |
|
1154 while ((tmp = g_node_first_child (tmp)) != NULL) { |
|
1155 TreeNode *tnode = tmp->data; |
|
1156 gchar *bname = tnode->orig; |
|
1157 gchar *dir = NULL; |
|
1158 gchar *newname = NULL; |
|
1159 |
|
1160 if (! TREENODE_IS_NEED_CONVERT (tnode)) { |
|
1161 continue; |
|
1162 } |
|
1163 |
|
1164 dir = fsexam_tree_get_path (tmp->parent, FALSE); |
|
1165 node_converted = real_convert (setting, dir, bname, &newname); |
|
1166 g_free (dir); |
|
1167 |
|
1168 if (node_converted) { |
|
1169 TREENODE_SET_CONVERTED (tnode, 1); |
|
1170 TREENODE_SET_UTF8 (tnode, newname); |
|
1171 |
|
1172 if ((G_NODE_IS_LEAF (tmp)) && (result_name != NULL)) { |
|
1173 /* last node */ |
|
1174 *result_name = fsexam_tree_get_path (tmp, FALSE); |
|
1175 } |
|
1176 }else{ |
|
1177 g_free (newname); |
|
1178 break; /* fsexam_errno store the reason */ |
|
1179 } |
|
1180 } |
|
1181 |
|
1182 setting->flags = 0; |
|
1183 fsexam_tree_destroy (root); |
|
1184 |
|
1185 return node_converted; |
|
1186 } |
|
1187 |
|
1188 gboolean |
|
1189 fsexam_convert_filename (FSEXAM_setting *setting, const gchar *filename) |
|
1190 { |
|
1191 g_return_val_if_fail (setting != NULL, FALSE); |
|
1192 |
|
1193 GList *list = NULL; |
|
1194 gboolean ret; |
|
1195 |
|
1196 if (filename != NULL) |
|
1197 list = g_list_prepend (list, (gpointer) filename); |
|
1198 |
|
1199 ret = fsexam_convert_filename_batch (setting, list); |
|
1200 |
|
1201 fsexam_list_free (list); |
|
1202 |
|
1203 return ret; |
|
1204 } |
|
1205 |
|
1206 gboolean |
|
1207 fsexam_convert_filename_batch (FSEXAM_setting *setting, GList *list) |
|
1208 { |
|
1209 g_return_val_if_fail (setting != NULL, FALSE); |
|
1210 |
|
1211 GNode *root = NULL; |
|
1212 |
|
1213 fsexam_setting_reset_stats (setting); |
|
1214 |
|
1215 if (list != NULL) |
|
1216 root = fsexam_tree_construct_from_list (list, setting); |
|
1217 |
|
1218 if ((NULL == list) || (NULL == root)){ |
|
1219 fsexam_errno = ERR_TREE_IS_EMPTY; |
|
1220 fsexam_log_puts (setting->log_info, NULL, NULL); |
|
1221 if (setting->display_msg) |
|
1222 setting->display_msg (NULL, fsexam_error_get_msg ()); |
|
1223 |
|
1224 return FALSE; |
|
1225 } |
|
1226 |
|
1227 if (fsexam_debug () |
|
1228 & (FSEXAM_DBG_OPTION | FSEXAM_DBG_TREE | FSEXAM_DBG_FILELIST)) { |
|
1229 return TRUE; |
|
1230 } |
|
1231 |
|
1232 setting->flags |= FSEXAM_SETTING_FLAGS_DIFF_SERIAL; |
|
1233 |
|
1234 g_node_traverse (root, |
|
1235 G_PRE_ORDER, |
|
1236 G_TRAVERSE_ALL, |
|
1237 -1, |
|
1238 convert_node, /* Return TRUE will stop the traverse */ |
|
1239 setting); |
|
1240 |
|
1241 setting->display_stats (setting); /* display statastics */ |
|
1242 fsexam_log_flush (setting->log_info); |
|
1243 setting->flags = 0; /* clear all flags after conversion */ |
|
1244 fsexam_tree_destroy (root); |
|
1245 |
|
1246 return TRUE; |
|
1247 } |
|
1248 |
|
1249 |
|
1250 //TODO: Add format validation |
|
1251 gboolean |
|
1252 fsexam_convert_scenario (FSEXAM_setting *setting) |
|
1253 { |
|
1254 g_return_val_if_fail (setting != NULL, FALSE); |
|
1255 |
|
1256 ConvType type; |
|
1257 gboolean ret; |
|
1258 |
|
1259 fsexam_setting_reset_stats (setting); |
|
1260 |
|
1261 if (setting->dryrun_info == NULL) { |
|
1262 fprintf (stderr, _("Can't access dry run result information.\n")); |
|
1263 return FALSE; |
|
1264 } |
|
1265 |
|
1266 if (!fsexam_dryrun_get_convtype (setting->dryrun_info, &type)) |
|
1267 return FALSE; |
|
1268 |
|
1269 if (type == ConvName) { |
|
1270 ret = fsexam_convert_scenario_for_name (setting); |
|
1271 }else{ |
|
1272 ret = fsexam_convert_scenario_for_content (setting); |
|
1273 } |
|
1274 |
|
1275 return ret; |
|
1276 } |
|
1277 |
|
1278 gboolean |
|
1279 fsexam_restore (FSEXAM_setting *setting, GList *list, ConvType restore_type) |
|
1280 { |
|
1281 gboolean ret; |
|
1282 |
|
1283 fsexam_setting_reset_stats (setting); |
|
1284 |
|
1285 if (restore_type == RestoreConvName) { |
|
1286 ret = fsexam_restore_name (setting, list); |
|
1287 }else if (restore_type == RestoreConvContent) { |
|
1288 ret = fsexam_restore_content (setting, list); |
|
1289 }else{ |
|
1290 g_print (_("Don't support this restore type.\n")); |
|
1291 ret = FALSE; |
|
1292 } |
|
1293 |
|
1294 return ret; |
|
1295 } |
|
1296 |
|
1297 |
|
1298 /* --------------- call back function for CLI ------------ */ |
|
1299 |
|
1300 #define INPUT_LEN 10 |
|
1301 |
|
1302 /* |
|
1303 * Get the index of user's selection. |
|
1304 * -1 returned if no selection. |
|
1305 */ |
|
1306 gint |
|
1307 get_index_default (GList *encoding_list, gboolean forname) |
|
1308 { |
|
1309 gint num_candidate; |
|
1310 gchar input[INPUT_LEN]; |
|
1311 gint response; |
|
1312 gint result_index; |
|
1313 |
|
1314 num_candidate = construct_candidate_list (encoding_list, forname); |
|
1315 |
|
1316 if (num_candidate < 1) { |
|
1317 fprintf (stderr, _("No proper encoding.\n")); |
|
1318 return -1; |
|
1319 } |
|
1320 |
|
1321 do { |
|
1322 fprintf (stdout, _("Please select No.('s' to skip): ")); |
|
1323 memset (input, 0, sizeof (input)); |
|
1324 fflush (stdin); /* discard excess data */ |
|
1325 fgets (input, sizeof(input), stdin); |
|
1326 |
|
1327 if ((*input == '\n') || (*input == '\0')) /* Return or Empty */ |
|
1328 continue; |
|
1329 |
|
1330 input[strlen (input) - 1] = '\0'; /* remove trailing '\n' */ |
|
1331 |
|
1332 if (g_ascii_strcasecmp (input, "s") == 0) { |
|
1333 response = -1; |
|
1334 break; |
|
1335 }else{ |
|
1336 gchar *tmp = input; |
|
1337 |
|
1338 for (; ((*tmp >= '0') && (*tmp <= '9') && (*tmp != '\0')); tmp++) |
|
1339 ; |
|
1340 |
|
1341 if (*tmp != '\0') |
|
1342 continue; |
|
1343 |
|
1344 response = atoi (input); /* input belong [0-9]{1, 9} */ |
|
1345 |
|
1346 if ((response < 0) || (response > num_candidate - 1)) |
|
1347 continue; |
|
1348 else |
|
1349 break; |
|
1350 } |
|
1351 } while (TRUE); |
|
1352 |
|
1353 if (response == -1) |
|
1354 return -1; |
|
1355 |
|
1356 fsexam_encoding_iterate_with_func (encoding_list, |
|
1357 fsexam_encoding_translate_index, |
|
1358 &response, |
|
1359 &result_index); |
|
1360 |
|
1361 return result_index; |
|
1362 } |
|
1363 |
|
1364 /* |
|
1365 * display_msg func for CLI |
|
1366 */ |
|
1367 void |
|
1368 display_msg_default (const gchar *filename, const gchar *msg) |
|
1369 { |
|
1370 if ((filename == NULL) || (msg == NULL)) |
|
1371 return; |
|
1372 |
|
1373 if (filename) { |
|
1374 if (g_utf8_validate (filename, -1, NULL)) { |
|
1375 fprintf (stderr, "%s: %s\n", filename, msg ? msg : ""); |
|
1376 }else{ |
|
1377 gchar *uri = g_filename_to_uri (filename, NULL, NULL); |
|
1378 |
|
1379 if (uri == NULL) { /* such as filename doesn't exist */ |
|
1380 uri = fsexam_string_escape (filename); |
|
1381 } |
|
1382 |
|
1383 fprintf (stderr, "%s: %s\n", uri, msg ? msg : ""); |
|
1384 g_free (uri); |
|
1385 } |
|
1386 }else{ |
|
1387 fprintf (stderr, "%s\n", msg); |
|
1388 } |
|
1389 |
|
1390 return; |
|
1391 } |
|
1392 |