Line data Source code
1 : /**
2 : * @file ftwin.c
3 : * @brief Main application logic for ftwin, including argument parsing, file traversal, and duplicate reporting.
4 : * @ingroup CoreLogic
5 : */
6 : /*
7 : *
8 : * Copyright (C) 2007 François Pesce : francois.pesce (at) gmail (dot) com
9 : *
10 : * Licensed under the Apache License, Version 2.0 (the "License");
11 : * you may not use this file except in compliance with the License.
12 : * You may obtain a copy of the License at
13 : *
14 : * http://www.apache.org/licenses/LICENSE-2.0
15 : *
16 : * Unless required by applicable law or agreed to in writing, software
17 : * distributed under the License is distributed on an "AS IS" BASIS,
18 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 : * See the License for the specific language governing permissions and
20 : * limitations under the License.
21 : */
22 :
23 : #include <unistd.h> /* getegid */
24 : #include <stdio.h> /* fgetgrent */
25 : #include <sys/stat.h> /* umask */
26 : #include <grp.h> /* fgetgrent */
27 :
28 : #include <apr_file_io.h>
29 : #include <apr_strings.h>
30 : #include <apr_user.h>
31 :
32 : #include "config.h"
33 :
34 : #include "debug.h"
35 : #include "ft_file.h"
36 : #include "ft_system.h"
37 : #include "human_size.h"
38 : #include "napr_threadpool.h"
39 : #include "ft_types.h"
40 : #include "ft_config.h"
41 : #include "ft_traverse.h"
42 : #include "ft_process.h"
43 : #include "ft_archive.h"
44 : #include "ft_report.h"
45 : #include "ft_report_json.h"
46 : #include "ft_image.h"
47 : #include "key_hash.h"
48 :
49 : int ft_file_cmp(const void *param1, const void *param2);
50 :
51 224 : const void *ft_fsize_get_key(const void *opaque)
52 : {
53 224 : const ft_fsize_t *fsize = opaque;
54 :
55 224 : return &(fsize->val);
56 : }
57 :
58 17 : const void *ft_gids_get_key(const void *opaque)
59 : {
60 17 : const ft_gid_t *gid = opaque;
61 :
62 17 : return &(gid->val);
63 : }
64 :
65 17 : int ftwin_main(int argc, const char **argv)
66 : {
67 : char errbuf[128];
68 : ft_conf_t *conf;
69 : apr_pool_t *pool, *gc_pool;
70 : int i, first_arg_index;
71 : apr_status_t status;
72 :
73 17 : if (APR_SUCCESS != (status = apr_initialize())) {
74 0 : DEBUG_ERR("error calling apr_initialize: %s", apr_strerror(status, errbuf, 128));
75 0 : return -1;
76 : }
77 :
78 17 : if (APR_SUCCESS != (status = apr_pool_create(&pool, NULL))) {
79 0 : DEBUG_ERR("error calling apr_pool_create: %s", apr_strerror(status, errbuf, 128));
80 0 : apr_terminate();
81 0 : return -1;
82 : }
83 :
84 17 : conf = ft_config_create(pool);
85 17 : if (APR_SUCCESS != (status = ft_config_parse_args(conf, argc, argv, &first_arg_index))) {
86 : /* Error message is printed inside the function */
87 0 : apr_terminate();
88 0 : return -1;
89 : }
90 :
91 : /* Step 1 : Browse the file */
92 17 : if (APR_SUCCESS != (status = apr_pool_create(&gc_pool, pool))) {
93 0 : DEBUG_ERR("error calling apr_pool_create: %s", apr_strerror(status, errbuf, 128));
94 0 : apr_terminate();
95 0 : return -1;
96 : }
97 40 : for (i = first_arg_index; i < argc; i++) {
98 23 : const char *current_arg = argv[i];
99 23 : char *resolved_path = (char *) current_arg;
100 :
101 : // Requirement: JSON output must contain absolute paths.
102 23 : if (is_option_set(conf->mask, OPTION_JSON)) {
103 : // Use apr_filepath_merge with NULL rootpath to resolve the absolute path.
104 3 : status = apr_filepath_merge(&resolved_path, NULL, current_arg, APR_FILEPATH_TRUENAME, gc_pool);
105 3 : if (APR_SUCCESS != status) {
106 0 : DEBUG_ERR("Error resolving absolute path for argument %s: %s.", current_arg,
107 : apr_strerror(status, errbuf, 128));
108 0 : apr_terminate();
109 0 : return -1; // Fail if path resolution fails for JSON mode
110 : }
111 : }
112 :
113 23 : if (APR_SUCCESS != (status = ft_traverse_path(conf, resolved_path))) {
114 0 : DEBUG_ERR("error calling ft_traverse_path: %s", apr_strerror(status, errbuf, 128));
115 0 : apr_terminate();
116 0 : return -1;
117 : }
118 : }
119 :
120 17 : if (0 < napr_heap_size(conf->heap)) {
121 17 : if (is_option_set(conf->mask, OPTION_PUZZL)) {
122 : #if HAVE_JANSSON
123 0 : if (is_option_set(conf->mask, OPTION_JSON)) {
124 0 : fprintf(stderr, "Error: JSON output is currently not supported in image comparison mode (-I).\n");
125 0 : apr_terminate();
126 0 : return -1;
127 : }
128 : #endif
129 : /* Step 2: Report the image twins */
130 0 : if (APR_SUCCESS != (status = ft_image_twin_report(conf))) {
131 0 : DEBUG_ERR("error calling ft_image_twin_report: %s", apr_strerror(status, errbuf, 128));
132 0 : apr_terminate();
133 0 : return status;
134 : }
135 : }
136 : else {
137 : /* Step 2: Process the sizes set */
138 17 : if (APR_SUCCESS != (status = ft_process_files(conf))) {
139 0 : DEBUG_ERR("error calling ft_process_files: %s", apr_strerror(status, errbuf, 128));
140 0 : apr_terminate();
141 0 : return -1;
142 : }
143 :
144 : #if HAVE_JANSSON
145 17 : if (is_option_set(conf->mask, OPTION_JSON)) {
146 1 : if (APR_SUCCESS != (status = ft_report_json(conf))) {
147 0 : DEBUG_ERR("error calling ft_report_json: %s", apr_strerror(status, errbuf, 128));
148 0 : apr_terminate();
149 0 : return status;
150 : }
151 : }
152 : else {
153 : #endif
154 16 : if (APR_SUCCESS != (status = ft_report_duplicates(conf))) {
155 0 : DEBUG_ERR("error calling ft_report_duplicates: %s", apr_strerror(status, errbuf, 128));
156 0 : apr_terminate();
157 0 : return status;
158 : }
159 : #if HAVE_JANSSON
160 : }
161 : #endif
162 : }
163 : }
164 : else {
165 0 : fprintf(stderr, "Please submit at least two files...\n");
166 0 : return -1;
167 : }
168 :
169 17 : apr_terminate();
170 :
171 17 : return 0;
172 : }
173 :
174 : #ifndef FTWIN_TEST_BUILD
175 : int main(int argc, const char **argv)
176 : {
177 : return ftwin_main(argc, argv);
178 : }
179 : #endif
|