"Fossies" - the Fresh Open Source Software Archive 
Member "detox-1.4.5/src/file.c" (15 Aug 2021, 7559 Bytes) of package /linux/privat/detox-1.4.5.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "file.c" see the
Fossies "Dox" file reference documentation.
1 /**
2 * This file is part of the Detox package.
3 *
4 * Copyright (c) Doug Harple <detox.dharple@gmail.com>
5 *
6 * For the full copyright and license information, please view the LICENSE
7 * file that was distributed with this source code.
8 */
9
10 #include "config.h"
11
12 #include <sys/stat.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <dirent.h>
17 #include <string.h>
18 #include <errno.h>
19
20 #include "clean_string.h"
21 #include "file.h"
22 #include "detox.h"
23
24 static char badfiles[3][30] = {
25 ".",
26 "..",
27 ""
28 };
29
30 #define BUF_SIZE 1024
31
32 /*
33 * Internal function declarations
34 */
35 static int ignore_file(unsigned char *filename, struct detox_options *options);
36
37 /*
38 * Renames file to a safe filename.
39 */
40 unsigned char *parse_file(unsigned char *filename, struct detox_options *options)
41 {
42 unsigned char *old_filename, *old_filename_ptr, *new_filename;
43 unsigned char *work, *hold;
44
45 struct stat stat_info_old;
46 struct stat stat_info_new;
47 int err;
48 size_t len;
49
50 struct detox_sequence_entry *sequence;
51
52 len = strlen(filename) + 1;
53 old_filename = malloc(len);
54 if (old_filename == NULL) {
55 fprintf(stderr, "out of memory: %s\n", strerror(errno));
56 return NULL;
57 }
58 memcpy(old_filename, filename, len);
59
60 old_filename_ptr = strrchr(old_filename, '/');
61 if (old_filename_ptr != NULL) {
62 old_filename_ptr++;
63 }
64 else {
65 old_filename_ptr = old_filename;
66 }
67
68 /*
69 * Check for files that need to be ignored
70 */
71
72 if (ignore_file(old_filename_ptr, options)) {
73 return old_filename;
74 }
75
76 /*
77 * Do the actual filename cleaning
78 */
79
80 sequence = options->sequence_to_use;
81
82 work = strdup(old_filename_ptr);
83
84 while (sequence != NULL && work != NULL) {
85 hold = sequence->cleaner(work, sequence->options);
86 if (work != NULL) {
87 free(work);
88 }
89 work = hold;
90
91 sequence = sequence->next;
92 }
93
94 if (work == NULL) {
95 return old_filename;
96 }
97
98 /* check to see if nothing changed */
99 if (strcmp(old_filename_ptr, work) == 0) {
100 return old_filename;
101 }
102
103 len = (old_filename_ptr - old_filename);
104 new_filename = malloc(len + strlen(work) + 1);
105 if (new_filename == NULL) {
106 fprintf(stderr, "out of memory: %s\n", strerror(errno));
107 free(work);
108 free(old_filename);
109 return NULL;
110 }
111
112 strncpy(new_filename, old_filename, len);
113 strcpy(new_filename + len, work);
114
115 free(work);
116
117 err = lstat(old_filename, &stat_info_old);
118 if (err == -1) {
119 free(new_filename);
120 return old_filename;
121 }
122
123 err = lstat(new_filename, &stat_info_new);
124 if (err != -1) { // New file exists
125 if (stat_info_old.st_dev != stat_info_new.st_dev || // Different device
126 stat_info_old.st_ino != stat_info_new.st_ino || // Different inode
127 stat_info_old.st_nlink > 1) // More than one hard link
128 {
129 fprintf(stderr, "Cannot rename %s to %s: file already exists\n", old_filename, new_filename);
130
131 free(new_filename);
132 return old_filename;
133 }
134 }
135
136 if (options->verbose || options->dry_run) {
137 printf("%s -> %s\n", old_filename, new_filename);
138 }
139
140 if (options->dry_run) {
141 free(new_filename);
142 return old_filename;
143 }
144
145 err = rename(old_filename, new_filename);
146 if (err == -1) {
147 fprintf(stderr, "Cannot rename %s to %s: %s\n", old_filename, new_filename, strerror(errno));
148 free(new_filename);
149 return old_filename;
150 }
151
152 free(old_filename);
153
154 return new_filename;
155 }
156
157 /*
158 * Handles directory.
159 */
160 void parse_dir(unsigned char *indir, struct detox_options *options)
161 {
162 unsigned char *new_file, *work;
163 DIR *dir_handle;
164 struct dirent *dir_entry;
165 struct stat stat_info;
166 int check_file;
167 int err;
168 size_t new_file_length;
169
170 err = lstat(indir, &stat_info);
171 if (err == -1) {
172 return;
173 }
174
175 if (!S_ISDIR(stat_info.st_mode)) {
176 return;
177 }
178
179 new_file_length = strlen(indir) + 1024;
180 new_file = (char *)malloc(new_file_length);
181 if (new_file == NULL) {
182 fprintf(stderr, "out of memory: %s\n", strerror(errno));
183 return;
184 }
185
186 /*
187 * Parse directory
188 */
189
190 dir_handle = opendir(indir);
191 if (dir_handle == NULL) {
192 fprintf(stderr, "unable to parse: %s\n", strerror(errno));
193 free(new_file);
194 return;
195 }
196
197 dir_entry = readdir(dir_handle);
198
199 while (dir_entry != NULL) {
200
201 /*
202 * Check for files that need to be ignored
203 */
204 check_file = !ignore_file(dir_entry->d_name, options);
205
206 if (check_file) {
207 snprintf(new_file, new_file_length, "%s/%s", indir, dir_entry->d_name);
208
209 lstat(new_file, &stat_info);
210 if (S_ISDIR(stat_info.st_mode)) {
211 work = parse_file(new_file, options);
212 if (options->recurse) {
213 parse_dir(work, options);
214 }
215 free(work);
216 }
217 else if (S_ISREG(stat_info.st_mode)) {
218 work = parse_file(new_file, options);
219 free(work);
220 }
221 else if (options->special) {
222 parse_special(new_file, options);
223 }
224 }
225 dir_entry = readdir(dir_handle);
226 }
227 closedir(dir_handle);
228 }
229
230 /*
231 * Handles a special file.
232 */
233 void parse_special(unsigned char *in, struct detox_options *options)
234 {
235 struct stat stat_info;
236 char *new_file, *work;
237 int err;
238
239 /* detox, then parse_dir if a symlink to a dir */
240 new_file = parse_file(in, options);
241 if (!new_file) {
242 return;
243 }
244
245 err = lstat(new_file, &stat_info);
246 if (err == -1) {
247 fprintf(stderr, "Unable to stat %s\n", in);
248 free(new_file);
249 return;
250 }
251
252 if (options->recurse && S_ISLNK(stat_info.st_mode)) {
253 work = malloc(1024);
254 if (!work) {
255 fprintf(stderr, "out of memory: %s\n", strerror(errno));
256 free(new_file);
257 return;
258 }
259
260 memset(work, 0, 1024);
261 err = readlink(new_file, work, 1023);
262 if (err == -1) {
263 fprintf(stderr, "Unable to read symbolic link %s\n", in);
264 free(work);
265 free(new_file);
266 return;
267 }
268
269 err = lstat(work, &stat_info);
270 if (err == -1) {
271 fprintf(stderr, "Unable to follow symbolic link %s\n", in);
272 free(work);
273 free(new_file);
274 return;
275 }
276
277 if (S_ISDIR(stat_info.st_mode)) {
278 parse_dir(work, options);
279 }
280
281 free(work);
282 }
283 free(new_file);
284
285 }
286
287 /*
288 * Determines if the file should be ignored
289 */
290 static int ignore_file(unsigned char *filename, struct detox_options *options)
291 {
292 struct detox_ignore_entry *ignore_walk;
293 int x;
294
295 for (x = 0; badfiles[x][0] != 0; x++) {
296 if (strcmp(filename, badfiles[x]) == 0) {
297 return 1;
298 }
299 }
300
301 ignore_walk = options->files_to_ignore;
302 while (ignore_walk != NULL) {
303 if (strcmp(filename, ignore_walk->filename) == 0) {
304 return 1;
305 }
306 ignore_walk = ignore_walk->next;
307 }
308
309 return 0;
310 }
311
312 /*
313 * Renames file to a safe filename.
314 */
315 void parse_inline(unsigned char *filename, struct detox_options *options)
316 {
317 struct detox_sequence_entry *sequence;
318 FILE *fp;
319 unsigned char *base, *work, *hold;
320 size_t buf_size;
321
322 if (filename != NULL) {
323 if (!(fp = fopen(filename, "r"))) {
324 fprintf(stderr, "%s: %s\n", filename, strerror(errno));
325 return;
326 }
327 }
328 else {
329 fp = stdin;
330 }
331
332 buf_size = BUF_SIZE;
333 base = malloc(buf_size);
334 if (base == NULL) {
335 fprintf(stderr, "out of memory: %s\n", strerror(errno));
336 return;
337 }
338
339 while (fgets(base, buf_size, fp)) {
340 while (strrchr(base, '\n') == NULL) {
341 work = realloc(base, buf_size + BUF_SIZE - 1);
342 if (!fgets(work + buf_size - 1, BUF_SIZE, fp)) {
343 base = work;
344 break;
345 }
346 base = work;
347 buf_size += BUF_SIZE - 1;
348 }
349
350 hold = strrchr(base, '\n');
351 if (hold == NULL) {
352 fprintf(stderr, "Unable to parse input\n");
353 exit(EXIT_FAILURE);
354 }
355 *hold = '\0';
356
357 work = strdup(base);
358
359 sequence = options->sequence_to_use;
360
361 while (sequence != NULL && work != NULL) {
362 hold = sequence->cleaner(work, sequence->options);
363 if (work != NULL) {
364 free(work);
365 }
366 work = hold;
367
368 sequence = sequence->next;
369 }
370
371 if (work != NULL) {
372 printf("%s\n", work);
373 }
374 else {
375 printf("\n");
376 }
377 }
378 }