1 /**************************************************************************************************
2 $Header: /pub/cvsroot/yencode/src/file.c,v 1.24 2002/03/15 14:48:52 bboy Exp $
3
4 Copyright (C) 2002 Don Moore <bboy@bboy.net>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at Your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 **************************************************************************************************/
20
21 #include "y.h"
22
23 extern char *opt_output_dir;
24 extern int opt_keep_paths; /* Strip paths from filenames? */
25
26 /* Static list of extensions for yencfile_cmp(). Must be seeded. */
27 static char **sort_first = (char **)NULL;
28 static int num_sort_first = 0;
29
30
31 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
32 Comparison function for sorting files.
33 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
34 int
ydecfile_cmp(const void * p1,const void * p2)35 ydecfile_cmp(const void *p1, const void *p2)
36 {
37 const YDECFILE *y1 = *(YDECFILE * const *)p1;
38 const YDECFILE *y2 = *(YDECFILE * const *)p2;
39 register int cmp;
40
41 if ((cmp = strcmp(y1->header->name, y2->header->name)))
42 return (cmp);
43 if (y1->header && y1->header->part && y2->header && y2->header->part)
44 return (*y1->header->part - *y2->header->part);
45 else
46 return (cmp);
47 }
48 /*--- ydecfile_cmp() ----------------------------------------------------------------------------*/
49
50
51 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
52 Allocate the YHEADER structure.
53 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
54 static YHEADER *
yheader_create(void)55 yheader_create(void)
56 {
57 YHEADER *new = (YHEADER *)xmalloc(sizeof(YHEADER));
58 memset(new, 0, sizeof(YHEADER));
59 return (new);
60 }
61 /*--- yheader_create() --------------------------------------------------------------------------*/
62
63
64 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
65 Allocate the YPART structure.
66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
67 static YPART *
ypart_create(void)68 ypart_create(void)
69 {
70 YPART *new = (YPART *)xmalloc(sizeof(YPART));
71 memset(new, 0, sizeof(YPART));
72 return (new);
73 }
74 /*--- ypart_create() ----------------------------------------------------------------------------*/
75
76
77 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
78 Allocate the YFOOTER structure.
79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
80 static YFOOTER *
yfooter_create(void)81 yfooter_create(void)
82 {
83 YFOOTER *new = (YFOOTER *)xmalloc(sizeof(YFOOTER));
84 memset(new, 0, sizeof(YFOOTER));
85 return (new);
86 }
87 /*--- yfooter_create() --------------------------------------------------------------------------*/
88
89
90 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
91 YDECFILE_ADD_YHEADER
92 Creates the YHEADER data (if necessary) and parses the input line to fill the header.
93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
94 static void
ydecfile_add_yheader(YDECFILE * y,char * line,unsigned long lineno,int strict)95 ydecfile_add_yheader(YDECFILE *y, char *line, unsigned long lineno, int strict)
96 {
97 char *cp;
98
99 if (y->header)
100 {
101 Notice("%s:%lu: %s", y->input_filename, lineno, _("duplicate `=ybegin' line ignored"));
102 return;
103 }
104 y->header = yheader_create();
105
106 if ((cp = strstr(line, " part=")))
107 {
108 y->header->part = (int *)xmalloc(sizeof(int));
109 *y->header->part = (int)strtoul(cp+6, (char **)NULL, 10);
110 }
111 if ((cp = strstr(line, " total=")))
112 {
113 y->header->total = (int *)xmalloc(sizeof(int));
114 *y->header->total = (int)strtoul(cp+7, (char **)NULL, 10);
115 }
116 if ((cp = strstr(line, " line=")))
117 {
118 y->header->line = (unsigned long *)xmalloc(sizeof(unsigned long));
119 *y->header->line = (unsigned long)strtoul(cp+6, (char **)NULL, 10);
120 }
121 if ((cp = strstr(line, " size=")))
122 {
123 y->header->size = (size_t *)xmalloc(sizeof(size_t));
124 *y->header->size = (size_t)strtoul(cp+6, (char **)NULL, 10);
125 }
126 if ((cp = strstr(line, " name=")))
127 {
128 char namebuf[PATH_MAX], *end;
129
130 strncpy(namebuf, cp+6, sizeof(namebuf)-1);
131 strtrim(namebuf);
132
133 /* v3 says we should handle filenames in quotation marks */
134 end = namebuf + strlen(namebuf) - 1;
135 if ((*namebuf == '"' && *end == '"') || (*namebuf == '\'' && *end == '\''))
136 {
137 *end = '\0';
138 y->header->name = xstrdup(strtrim(namebuf+1));
139 }
140 else
141 y->header->name = xstrdup(namebuf);
142 }
143
144 /* As of v2, decoders should be able to understand if the "begin" or "end"
145 occur in the =ybegin line */
146 if ((cp = strstr(line, " begin=")))
147 {
148 if (strict)
149 Info("%s:%lu: %s", y->input_filename, lineno, _("begin offset wrongly specified in the `=ybegin' header"));
150 y->header->begin = (unsigned long *)xmalloc(sizeof(unsigned long));
151 *y->header->begin = (unsigned long)strtoul(cp+7, (char **)NULL, 10);
152 }
153 if ((cp = strstr(line, " end=")))
154 {
155 if (strict)
156 Info("%s:%lu: %s", y->input_filename, lineno, _("end offset wrongly specified in the `=ybegin' header"));
157 y->header->end = (unsigned long *)xmalloc(sizeof(unsigned long));
158 *y->header->end = (unsigned long)strtoul(cp+5, (char **)NULL, 10);
159 }
160
161 if (!y->header->name)
162 {
163 free(y->header);
164 y->header = NULL;
165 return;
166 }
167 }
168 /*--- ydecfile_add_yheader() --------------------------------------------------------------------*/
169
170
171 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
172 YDECFILE_ADD_YPART
173 Creates the YPART data (if necessary) and parses the input line to fill the part information.
174 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
175 static void
ydecfile_add_ypart(YDECFILE * y,char * line,unsigned long lineno,int strict)176 ydecfile_add_ypart(YDECFILE *y, char *line, unsigned long lineno, int strict)
177 {
178 char *cp;
179
180 if (y->part)
181 {
182 Notice("%s:%lu: %s", y->input_filename, lineno, _("duplicate `=ypart' line ignored"));
183 return;
184 }
185 y->part = ypart_create();
186
187 if ((cp = strstr(line, " begin=")))
188 {
189 y->part->begin = (unsigned long *)xmalloc(sizeof(unsigned long));
190 *y->part->begin = (unsigned long)strtoul(cp+7, (char **)NULL, 10);
191 }
192 if ((cp = strstr(line, " end=")))
193 {
194 y->part->end = (unsigned long *)xmalloc(sizeof(unsigned long));
195 *y->part->end = (unsigned long)strtoul(cp+5, (char **)NULL, 10);
196 }
197 }
198 /*--- ydecfile_add_ypart() ----------------------------------------------------------------------*/
199
200
201 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
202 YDECFILE_ADD_YFOOTER
203 Creates the YFOOTER data (if necessary) and parses the input line to fill the footer info.
204 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
205 static void
ydecfile_add_yfooter(YDECFILE * y,char * line,unsigned long lineno,int strict)206 ydecfile_add_yfooter(YDECFILE *y, char *line, unsigned long lineno, int strict)
207 {
208 char *cp;
209
210 if (y->footer)
211 {
212 Notice("%s:%lu: %s", y->input_filename, lineno, _("duplicate `=yend' line ignored"));
213 return;
214 }
215 y->footer = yfooter_create();
216
217 if ((cp = strstr(line, " size=")))
218 {
219 y->footer->size = (size_t *)xmalloc(sizeof(size_t));
220 *y->footer->size = (size_t)strtoul(cp+6, (char **)NULL, 10);
221 }
222 if ((cp = strstr(line, " part=")))
223 {
224 y->footer->part = (int *)xmalloc(sizeof(int));
225 *y->footer->part = (int)strtoul(cp+6, (char **)NULL, 10);
226 }
227 if ((cp = strstr(line, " crc32=")))
228 {
229 y->footer->crc32 = (crc32_t *)xmalloc(sizeof(crc32_t));
230 *y->footer->crc32 = (crc32_t)strtoul(cp+7, (char **)NULL, 16);
231 }
232 if ((cp = strstr(line, " pcrc32=")))
233 {
234 y->footer->pcrc32 = (crc32_t *)xmalloc(sizeof(crc32_t));
235 *y->footer->pcrc32 = (crc32_t)strtoul(cp+8, (char **)NULL, 16);
236 }
237 }
238 /*--- ydecfile_add_yfooter() --------------------------------------------------------------------*/
239
240
241 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
242 YDECFILE_READ_KEYWORDS
243 Loads the ybegin and ypart information from the specified YDECFILE and returns.
244 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
245 static void
ydecfile_read_keywords(YDECFILE * y,int strict)246 ydecfile_read_keywords(YDECFILE *y, int strict)
247 {
248 FILE *fp;
249 unsigned char buf[BUFSIZ];
250 register int got_begin = 0;
251 register unsigned long lineno = 0;
252
253 if (!(fp = fopen(y->input_filename, "rb")))
254 ErrERR("%s", y->input_filename);
255
256 /* Find markers, calculating data length and CRC along the way */
257 while (fgets(buf, sizeof(buf), fp))
258 {
259 lineno++;
260
261 if (!YKEYWORD(buf))
262 continue;
263
264 if (YKEYWORD_BEGIN(buf))
265 {
266 ydecfile_add_yheader(y, buf, lineno, strict);
267 y->data_start = ftell(fp);
268 y->line_offset = lineno;
269 got_begin = 1;
270 }
271 else if (YKEYWORD_PART(buf))
272 {
273 ydecfile_add_ypart(y, buf, lineno, strict);
274 y->data_start = ftell(fp);
275 y->line_offset = lineno;
276 }
277 else if (YKEYWORD_END(buf))
278 {
279 ydecfile_add_yfooter(y, buf, lineno, strict);
280 fclose(fp);
281 return;
282 }
283 else
284 {
285 /* In my test file, there was binary garbage "=y" after a newline, so don't warn.. it
286 could output garbage and trash the terminal */
287 #ifdef notdef
288 unsigned char *c;
289
290 /* Try to isolate just the unknown keyword */
291 for (c = buf; *c; c++)
292 if (isspace(*c) || iscntrl(*c))
293 *c = '\0';
294
295 Info("%s:%lu: `%s': %s", y->input_filename, lineno, buf, _("unknown keyword ignored"));
296 #endif
297 }
298 }
299 fclose(fp);
300 }
301 /*--- ydecfile_read_keywords() ------------------------------------------------------------------*/
302
303
304 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
305 YDECFILE_VERIFY_KEYWORD_DATA
306 Verifies the markers in the specified YDECFILE. Returns a pointer to the YDECFILE or NULL if an
307 error occurred (and processing should not be done on this file).
308 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
309 static YDECFILE *
ydecfile_verify_keyword_data(YDECFILE * y,int strict)310 ydecfile_verify_keyword_data(YDECFILE *y, int strict)
311 {
312 /*
313 ** First, fix any data suspected of being broken but that we can extrapolate from elsewhere
314 */
315 /* The file is not valid if no header or footer were found */
316 if (!y->header || !y->footer)
317 return (NULL);
318
319 /* Copy part begin/end data from header if it was specified there (erroneously) */
320 if (y->header->begin && (!y->part || !y->part->begin))
321 {
322 if (!y->part)
323 y->part = ypart_create();
324 y->part->begin = (unsigned long *)xmalloc(sizeof(unsigned long));
325 *y->part->begin = *y->header->begin;
326 }
327 if (y->header->end && (!y->part || !y->part->end))
328 {
329 if (!y->part)
330 y->part = ypart_create();
331 y->part->end = (unsigned long *)xmalloc(sizeof(unsigned long));
332 *y->part->end = *y->header->end;
333 }
334
335 /* If no `end' was specified in =ypart, set it based on the size in the footer */
336 if (y->part && !y->part->end && y->footer->size)
337 {
338 y->part->end = (unsigned long *)xmalloc(sizeof(unsigned long));
339 *y->part->end = *y->part->begin + *y->footer->size - 1;
340 }
341
342
343 /*
344 ** Warn and/or die if vital data is missing
345 */
346 if (!y->header->line)
347 {
348 Notice("%s: %s (%s)", y->input_filename, _("line length not specified"), _("file will not be processed"));
349 return (NULL);
350 }
351 if (!y->header->name)
352 {
353 Notice("%s: %s (%s)", y->input_filename, _("output filename not specified"), _("file will not be processed"));
354 return (NULL);
355 }
356 if (!y->header->size)
357 {
358 Notice("%s: %s (%s)", y->input_filename, _("file size not specified"), _("file will not be processed"));
359 return (NULL);
360 }
361
362 return (y);
363 }
364 /*--- ydecfile_verify_keyword_data() ------------------------------------------------------------*/
365
366
367 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
368 Adds the specified file to the list pointed to by ylist_head. Errors are fatal.
369 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
370 YDECFILE *
ydecfile_create(const char * filename,int strict)371 ydecfile_create(const char *filename, int strict)
372 {
373 YDECFILE *y; // The new file
374 struct stat st; // File stat info
375
376 if (!filename)
377 return (NULL);
378 if (stat(filename, &st)) // Treat file as invalid
379 {
380 WarnERR("%s", filename);
381 return (NULL);
382 }
383 if (!S_ISREG(st.st_mode))
384 return (NULL);
385
386 /* Allocate structure and set default values */
387 y = (YDECFILE *)xmalloc(sizeof(YDECFILE));
388 memset(y, 0, sizeof(YDECFILE));
389 y->input_filename = xstrdup(filename);
390 y->input_st = (struct stat *)xmalloc(sizeof(struct stat));
391 memcpy(y->input_st, &st, sizeof(struct stat));
392
393 ydecfile_read_keywords(y, strict);
394
395 return (ydecfile_verify_keyword_data(y, strict));
396 }
397 /*--- ydecfile_create() -------------------------------------------------------------------------*/
398
399
400 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
401 Allocate the YENCPART structure.
402 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
403 YENCPART *
yencpart_create(void)404 yencpart_create(void)
405 {
406 YENCPART *new = (YENCPART *)xmalloc(sizeof(YENCPART));
407 memset(new, 0, sizeof(YENCPART));
408 return (new);
409 }
410 /*--- yencpart_create() -------------------------------------------------------------------------*/
411
412
413 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
414 YENCFILE_SEED_SORT_FIRST_EXTENSIONS
415 Seeds the list of extensions which should be sorted first by yencfile_cmp().
416 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
417 void
yencfile_seed_sort_first_extensions(const char * seedstr)418 yencfile_seed_sort_first_extensions(const char *seedstr)
419 {
420 char *ss, *c;
421
422 ss = (seedstr) ? xstrdup(seedstr) : xstrdup(DEFAULT_SORT_FIRST_EXTENSIONS);
423
424 while ((c = strsep(&ss, ",")))
425 {
426 strtrim(c);
427 if (c[0] == '.')
428 c++;
429 sort_first = (char **)xrealloc(sort_first, (num_sort_first + 1) * sizeof(char *));
430 sort_first[num_sort_first++] = c;
431 }
432 }
433 /*--- yencfile_seed_sort_first_extensions() -----------------------------------------------------*/
434
435
436 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
437 YENCFILE_CMP
438 Comparison function for sorting files.
439 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
440 int
yencfile_cmp(const void * p1,const void * p2)441 yencfile_cmp(const void *p1, const void *p2)
442 {
443 const YENCFILE *y1 = *(YENCFILE * const *)p1;
444 const YENCFILE *y2 = *(YENCFILE * const *)p2;
445
446 /* See if each file has an extension that should be sorted first */
447 if (num_sort_first)
448 {
449 char *y1ext, *y2ext;
450 int y1first, y2first;
451 register int ct;
452
453 y1ext = strrchr(y1->input_filename, '.');
454 y2ext = strrchr(y2->input_filename, '.');
455 for (ct = y1first = y2first = 0; ct < num_sort_first; ct++)
456 {
457 if (y1ext && !strcasecmp(y1ext+1, sort_first[ct]))
458 y1first = ct+1;
459 if (y2ext && !strcasecmp(y2ext+1, sort_first[ct]))
460 y2first = ct+1;
461 }
462 if (y1first && !y2first)
463 return (-1);
464 if (y2first && !y1first)
465 return (1);
466 if (y1first && y2first)
467 return (y1first - y2first);
468 }
469 return (strcmp(y1->input_filename, y2->input_filename));
470 }
471 /*--- yencfile_cmp() ----------------------------------------------------------------------------*/
472
473
474 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
475 YENCFILE_CREATE
476 Adds a file to the input file list.
477 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
478 YENCFILE *
yencfile_create(const char * input_filename,const char * output_dir,ysupportfile_t special_file_type,size_t multipart_size)479 yencfile_create(const char *input_filename, const char *output_dir,
480 ysupportfile_t special_file_type, size_t multipart_size)
481 {
482 YENCFILE *y;
483 struct stat st;
484 char *c, base_name[PATH_MAX], prefix[PATH_MAX];
485
486 y = (YENCFILE *)xmalloc(sizeof(YENCFILE));
487 memset(y, 0, sizeof(YENCFILE));
488
489 y->input_filename = xstrdup(input_filename);
490 y->file_type = special_file_type;
491
492 if (YSUPPORT_IS_SPECIAL(y->file_type))
493 return (y);
494
495 /* Check file, get filesize, create filename prefix */
496 if (stat(y->input_filename, &st))
497 ErrERR("%s", y->input_filename);
498 if (!S_ISREG(st.st_mode))
499 {
500 Debug("%s: %s", y->input_filename, _("not a regular file (skipped)"));
501 free(y);
502 return (NULL);
503 }
504 y->filesize = st.st_size;
505
506 /* Generate output prefix */
507 if ((c = strrchr(y->input_filename, '/'))) /* Copy basename of input file into `name' */
508 strncpy(base_name, c+1, sizeof(base_name)-1);
509 else
510 strncpy(base_name, y->input_filename, sizeof(base_name)-1);
511 if (output_dir) /* Generate prefix for output files */
512 snprintf(prefix, sizeof(prefix), "%s/%s", output_dir, base_name);
513 else
514 strncpy(prefix, base_name, sizeof(prefix)-1);
515 y->output_prefix = xstrdup(prefix);
516
517 /* Determine total number of parts if multipart */
518 if (multipart_size && (y->filesize > multipart_size))
519 {
520 y->totalparts = y->filesize / multipart_size;
521 if (y->filesize % multipart_size)
522 y->totalparts++;
523 }
524 else
525 y->totalparts = 1;
526
527 return (y);
528 }
529 /*--- yencfile_create() -------------------------------------------------------------------------*/
530
531 /* vi:set ts=3: */
532