1 /* xdelta 3 - delta compression tools and library
2 * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007,
3 * 2008, 2009, 2010, 2011
4 * Joshua P. MacDonald
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 /* This is all the extra stuff you need for convenience to users in a
22 * command line application. It contains these major components:
23 *
24 * 1. VCDIFF tools 2. external compression support (this is
25 * POSIX-specific). 3. a general read/write loop that handles all of
26 * the Xdelta decode/encode/VCDIFF-print functions 4. command-line
27 * interpreter 5. an Xdelta application header which stores default
28 * filename, external compression settings 6. output/error printing
29 * 7. basic file support and OS interface
30 */
31
32 /* On error handling and printing:
33 *
34 * The xdelta library sets stream->msg to indicate what condition
35 * caused an internal failure, but many failures originate here and
36 * are printed here. The return convention is 0 for success, as
37 * throughout Xdelta code, but special attention is required here for
38 * the operating system calls with different error handling. See the
39 * main_file_* routines. All errors in this file have a message
40 * printed at the time of occurance. Since some of these calls occur
41 * within calls to the library, the error may end up being printed
42 * again with a more general error message.
43 */
44
45 /*********************************************************************/
46
47 #ifndef XD3_POSIX
48 #define XD3_POSIX 0
49 #endif
50 #ifndef XD3_STDIO
51 #define XD3_STDIO 0
52 #endif
53 #ifndef XD3_WIN32
54 #define XD3_WIN32 0
55 #endif
56 #ifndef XD3_AMIGA
57 #define XD3_AMIGA 0
58 #endif
59
60 /* Combines xd3_strerror() and strerror() */
61 const char* xd3_mainerror(int err_num);
62
63 /* If none are set, default to posix. */
64 #if (XD3_POSIX + XD3_STDIO + XD3_WIN32 + XD3_AMIGA) == 0
65 #undef XD3_POSIX
66 #define XD3_POSIX 1
67 #endif
68
69 #define PRINTHDR_SPECIAL -4378291
70
71 /* this is used as in XPR(NT XD3_LIB_ERRMSG (stream, ret)) to print an
72 * error message from the library. */
73 #define XD3_LIB_ERRMSG(stream, ret) "%s: %s\n", \
74 xd3_errstring (stream), xd3_mainerror (ret)
75
76 #include <stdio.h> /* fprintf */
77
78 #if XD3_POSIX
79 #if !(defined(__OS2__)||defined(_WIN32))
80 #include <unistd.h> /* close, read, write... */
81 #else
82 #include <io.h>
83 #endif
84 #ifndef __DJGPP__
85 #include <sys/stat.h> /* stat() and fstat() */
86 #endif
87 #include <sys/types.h>
88 #include <fcntl.h>
89 #endif
90
91 #if XD3_STDIO && !defined(__DJGPP__)
92 #include <sys/stat.h> /* stat() and fstat() */
93 #endif
94
95 #if XD3_AMIGA
96 #include <proto/exec.h>
97 #include <proto/dos.h>
98 #endif
99
100 #ifdef __DJGPP__
101 #include <dos.h>
102 #include <io.h>
103 #include <unistd.h>
104 #endif
105
106 /**********************************************************************
107 ENUMS and TYPES
108 *********************************************************************/
109
110 /* main_file->mode values */
111 typedef enum
112 {
113 XO_READ = 0,
114 XO_WRITE = 1,
115 } main_file_modes;
116
117 typedef struct _main_file main_file;
118
119 /* The main_file object supports abstract system calls like open,
120 * close, read, write, seek, stat. The program uses these to
121 * represent both seekable files and non-seekable files. Source files
122 * must be seekable, but the target input and any output file do not
123 * require seekability.
124 */
125 struct _main_file
126 {
127 #if XD3_STDIO
128 FILE *file;
129 #elif XD3_POSIX
130 int file;
131 #elif XD3_WIN32
132 HANDLE file;
133 #elif XD3_AMIGA
134 BPTR file;
135 #endif
136
137 int mode; /* XO_READ and XO_WRITE */
138 const char *filename; /* File name. */
139 xoff_t nread; /* for input position */
140 xoff_t nwrite; /* for output position */
141 xoff_t source_position; /* for avoiding seek in getblk_func */
142 int seek_failed; /* after seek fails once, try FIFO */
143 };
144
145 #include "xdelta3-mainopt.h"
146
147 #define DEFAULT_VERBOSE 0
148
149 static xd3_options_t default_options =
150 {
151 XD3_DEFAULT_IOPT_SIZE, /* iopt_size */
152 XD3_DEFAULT_WINSIZE, /* winsize */
153 XD3_DEFAULT_SRCWINSZ, /* srcwinsz */
154 XD3_DEFAULT_SPREVSZ, /* sprevsz */
155
156 1, /* force overwrite */ /* was 0. */
157 DEFAULT_VERBOSE, /* verbose */
158 1, /* use_checksum */
159
160 NULL, /* progress data */
161 NULL, /* debug_print () */
162 NULL /* progress_log() */
163 };
164 static xd3_options_t *use_options = &default_options;
165
166 /* Static variables */
167 static uint8_t* main_bdata = NULL;
168 static usize_t main_bsize = 0;
169
170 static int main_input (main_file *ifile,
171 main_file *ofile, main_file *sfile);
172
173 static int main_getblk_func (xd3_stream *stream,
174 xd3_source *source,
175 xoff_t blkno);
176 static void main_free (void *ptr);
177 static void* main_malloc (usize_t size);
178
179 static int main_file_open (main_file *xfile, const char* name, int mode);
180 static int main_file_stat (main_file *xfile, xoff_t *size);
181 static int main_file_seek (main_file *xfile, xoff_t pos);
182 static int main_read_primary_input (main_file *file,
183 uint8_t *buf,
184 usize_t size,
185 usize_t *nread);
186
187 /* The code in xdelta3-blk.h is essentially part of this unit, see
188 * comments there. */
189 #include "xdelta3-blkcache.h"
190
191 static void
reset_defaults(void)192 reset_defaults(void)
193 {
194 use_options = &default_options;
195
196 main_bdata = NULL;
197 main_bsize = 0;
198
199 main_lru_reset();
200 }
201
202 static void*
main_malloc1(usize_t size)203 main_malloc1 (usize_t size)
204 {
205 void* r = malloc (size);
206 if (r == NULL && use_options->debug_print)
207 use_options->debug_print("malloc: %s\n", xd3_mainerror (ENOMEM));
208 return r;
209 }
210
211 static void*
main_malloc(usize_t size)212 main_malloc (usize_t size)
213 {
214 void *r = main_malloc1 (size);
215 return r;
216 }
217
218 static void*
main_alloc(void * opaque,usize_t items,usize_t size)219 main_alloc (void *opaque,
220 usize_t items,
221 usize_t size)
222 {
223 return main_malloc1 (items * size);
224 }
225
226 static void
main_free1(void * opaque,void * ptr)227 main_free1 (void *opaque, void *ptr)
228 {
229 free (ptr);
230 }
231
232 static void
main_free(void * ptr)233 main_free (void *ptr)
234 {
235 if (ptr)
236 {
237 main_free1 (NULL, ptr);
238 }
239 }
240
241 /* This ensures that (ret = errno) always indicates failure, in case errno was
242 * accidentally not set. If this prints there's a bug somewhere. */
243 static int
get_errno(void)244 get_errno (void)
245 {
246 #if defined(_WIN32)
247 DWORD err_num = GetLastError();
248 if (err_num == NO_ERROR)
249 {
250 err_num = XD3_INTERNAL;
251 }
252 return err_num;
253 #elif (XD3_AMIGA)
254 switch (IoErr()) {
255 case ERROR_OBJECT_NOT_FOUND:
256 return ENOENT;
257 case ERROR_DISK_FULL:
258 return ENOSPC;
259 default:
260 return EIO; /* better ?? */
261 }
262 #else
263 if (errno == 0)
264 {
265 if (use_options->debug_print)
266 use_options->debug_print("BUG: expected errno != 0\n");
267 errno = XD3_INTERNAL;
268 }
269 return errno;
270 #endif
271 }
272
273 const char*
xd3_mainerror(int err_num)274 xd3_mainerror(int err_num) {
275 #if !(defined(_WIN32) || defined(_WIN64))
276 const char* x = xd3_strerror (err_num);
277 if (x != NULL)
278 {
279 return x;
280 }
281 return strerror(err_num);
282 #else
283 static char err_buf[256];
284 const char* x = xd3_strerror (err_num);
285 if (x != NULL)
286 {
287 return x;
288 }
289 memset (err_buf, 0, 256);
290 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM |
291 FORMAT_MESSAGE_IGNORE_INSERTS,
292 NULL, err_num,
293 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
294 err_buf, 256, NULL);
295 if (err_buf[0] != 0 && err_buf[strlen(err_buf) - 1] == '\n')
296 {
297 err_buf[strlen(err_buf) - 1] = 0;
298 }
299 return err_buf;
300 #endif
301 }
302
303 /******************************************************************
304 FILE BASICS
305 ******************************************************************/
306
307 /* With all the variation in file system-call semantics, arguments,
308 * return values and error-handling for the POSIX and STDIO file APIs,
309 * the insides of these functions make me sick, which is why these
310 * wrappers exist. */
311
312 /* dos/windows needs opening files in binary mode */
313 #if !defined(O_BINARY)
314 # if defined(_O_BINARY)
315 # define O_BINARY _O_BINARY
316 # else
317 # define O_BINARY 0
318 # endif
319 #endif
320
321 #define XOPEN_OPNAME (xfile->mode == XO_READ ? "read" : "write")
322 #define XOPEN_STDIO (xfile->mode == XO_READ ? "rb" : "wb")
323 #define XOPEN_POSIX (xfile->mode == XO_READ ? (O_RDONLY | O_BINARY) : \
324 (O_WRONLY | O_CREAT | O_TRUNC | O_BINARY))
325 #define XOPEN_MODE (xfile->mode == XO_READ ? 0 : 0666)
326 #define XOPEN_AMIGA (xfile->mode == XO_READ ? MODE_OLDFILE : MODE_NEWFILE)
327
328 #define XF_ERROR(op, name, ret) \
329 do { \
330 if (use_options->debug_print != NULL) { \
331 use_options->debug_print("file %s failed: %s: %s: %s\n", (op), \
332 XOPEN_OPNAME, (name), xd3_mainerror (ret)); \
333 } \
334 } while (0)
335
336 #if XD3_STDIO
337 #define XFNO(f) fileno(f->file)
338 #elif XD3_POSIX
339 #define XFNO(f) f->file
340 #elif XD3_WIN32
341 #define XFNO(f) -1
342 #elif XD3_AMIGA
343 #define XFNO(f) -1
344 #endif
345
346 static void
main_file_init(main_file * xfile)347 main_file_init (main_file *xfile)
348 {
349 memset (xfile, 0, sizeof (*xfile));
350
351 #if XD3_POSIX
352 xfile->file = -1;
353 #endif
354 #if XD3_WIN32
355 xfile->file = INVALID_HANDLE_VALUE;
356 #endif
357 }
358
359 static int
main_file_isopen(main_file * xfile)360 main_file_isopen (main_file *xfile)
361 {
362 #if XD3_STDIO
363 return xfile->file != NULL;
364
365 #elif XD3_POSIX
366 return xfile->file != -1;
367
368 #elif XD3_WIN32
369 return xfile->file != INVALID_HANDLE_VALUE;
370
371 #elif XD3_AMIGA
372 return xfile->file != 0;
373 #endif
374 }
375
376 static int
main_file_close(main_file * xfile)377 main_file_close (main_file *xfile)
378 {
379 int ret = 0;
380
381 if (! main_file_isopen (xfile))
382 {
383 return 0;
384 }
385
386 #if XD3_STDIO
387 ret = fclose (xfile->file);
388 xfile->file = NULL;
389
390 #elif XD3_POSIX
391 ret = close (xfile->file);
392 xfile->file = -1;
393
394 #elif XD3_WIN32
395 if (!CloseHandle(xfile->file)) {
396 ret = get_errno ();
397 }
398 xfile->file = INVALID_HANDLE_VALUE;
399
400 #elif XD3_AMIGA
401 ret = !Close (xfile->file);
402 xfile->file = 0;
403 if (ret) ret = get_errno ();
404 #endif
405
406 if (ret != 0) { XF_ERROR ("close", xfile->filename, ret = get_errno ()); }
407 return ret;
408 }
409
410 static void
main_file_cleanup(main_file * xfile)411 main_file_cleanup (main_file *xfile)
412 {
413 XD3_ASSERT (xfile != NULL);
414
415 if (main_file_isopen (xfile))
416 {
417 main_file_close (xfile);
418 }
419 }
420
421 static int
main_file_open(main_file * xfile,const char * name,int mode)422 main_file_open (main_file *xfile, const char* name, int mode)
423 {
424 int ret = 0;
425
426 xfile->mode = mode;
427
428 XD3_ASSERT (name != NULL);
429 XD3_ASSERT (! main_file_isopen (xfile));
430 if (name[0] == 0)
431 {
432 if (use_options->debug_print)
433 use_options->debug_print("invalid file name: empty string\n");
434 return XD3_INVALID;
435 }
436
437 #if XD3_STDIO
438 xfile->file = fopen (name, XOPEN_STDIO);
439
440 ret = (xfile->file == NULL) ? get_errno () : 0;
441
442 #elif XD3_POSIX
443 if ((ret = open (name, XOPEN_POSIX, XOPEN_MODE)) == -1)
444 {
445 ret = get_errno ();
446 }
447 else
448 {
449 xfile->file = ret;
450 ret = 0;
451 }
452
453 #elif XD3_WIN32
454 xfile->file = CreateFile(name,
455 (mode == XO_READ) ? GENERIC_READ : GENERIC_WRITE,
456 FILE_SHARE_READ,
457 NULL,
458 (mode == XO_READ) ?
459 OPEN_EXISTING :
460 (use_options->overwrite ? CREATE_ALWAYS : CREATE_NEW),
461 FILE_ATTRIBUTE_NORMAL,
462 NULL);
463 if (xfile->file == INVALID_HANDLE_VALUE)
464 {
465 ret = get_errno ();
466 }
467
468 #elif XD3_AMIGA
469 xfile->file = Open((const STRPTR) name, XOPEN_AMIGA);
470 ret = (xfile->file == 0) ? get_errno () : 0;
471 #endif
472 if (ret) { XF_ERROR ("open", name, ret); }
473 else { xfile->nread = 0; }
474 return ret;
475 }
476
477 static int
main_file_stat(main_file * xfile,xoff_t * size)478 main_file_stat (main_file *xfile, xoff_t *size)
479 {
480 #if XD3_WIN32
481 if (GetFileType(xfile->file) != FILE_TYPE_DISK)
482 {
483 return -1;
484 }
485 # if (_WIN32_WINNT >= 0x0500)
486 {
487 LARGE_INTEGER li;
488 if (GetFileSizeEx(xfile->file, &li) == 0)
489 {
490 return get_errno ();
491 }
492 *size = li.QuadPart;
493 }
494 # else
495 {
496 DWORD filesize = GetFileSize(xfile->file, NULL);
497 DWORD err_num;
498 if (filesize == INVALID_FILE_SIZE)
499 {
500 err_num = GetLastError();
501 if (err_num != NO_ERROR)
502 {
503 return err_num;
504 }
505 }
506 *size = filesize;
507 }
508 # endif
509 #elif defined(__DJGPP__)
510 long filesize = filelength (XFNO (xfile));
511 if (filesize == -1)
512 {
513 return get_errno ();
514 }
515 *size = filesize;
516 #elif (XD3_AMIGA)
517 struct FileInfoBlock *fib = (struct FileInfoBlock*)
518 AllocDosObject(DOS_FIB, NULL);
519 long filesize = -1;
520 if (fib != NULL)
521 {
522 if (ExamineFH(xfile->file, fib))
523 filesize = fib->fib_Size;
524 FreeDosObject(DOS_FIB, fib);
525 }
526 if (filesize < 0)
527 return get_errno ();
528 *size = filesize;
529 #else
530 struct stat sbuf;
531 if (fstat (XFNO (xfile), & sbuf) == -1)
532 {
533 return get_errno ();
534 }
535
536 if (! S_ISREG (sbuf.st_mode))
537 {
538 return ESPIPE;
539 }
540 (*size) = sbuf.st_size;
541 #endif
542 return 0;
543 }
544
545 #if (XD3_POSIX)
546 /* POSIX-generic code takes a function pointer to read() or write().
547 * This calls the function repeatedly until the buffer is full or EOF.
548 * The NREAD parameter is not set for write, NULL is passed. Return
549 * is signed, < 0 indicate errors, otherwise byte count. */
550 typedef int (xd3_posix_func) (int fd, uint8_t *buf, usize_t size);
551
552 static int
xd3_posix_io(int fd,uint8_t * buf,usize_t size,xd3_posix_func * func,usize_t * nread)553 xd3_posix_io (int fd, uint8_t *buf, usize_t size,
554 xd3_posix_func *func, usize_t *nread)
555 {
556 int ret;
557 usize_t nproc = 0;
558
559 while (nproc < size)
560 {
561 int result = (*func) (fd, buf + nproc, size - nproc);
562
563 if (result < 0)
564 {
565 ret = get_errno ();
566 if (ret != EAGAIN && ret != EINTR)
567 {
568 return ret;
569 }
570 continue;
571 }
572
573 if (nread != NULL && result == 0) { break; }
574
575 nproc += result;
576 }
577 if (nread != NULL) { (*nread) = nproc; }
578 return 0;
579 }
580 #endif
581
582 #if (XD3_AMIGA)
583 /* Read() and Write() are unbuffered. This calls Read() or Write()
584 * repeatedly until the buffer is full or EOF.
585 * The NREAD parameter is not set for write, NULL is passed. Return
586 * is signed, < 0 indicate errors, otherwise byte count. */
587 static int
xd3_amiga_io(BPTR fd,uint8_t * buf,usize_t size,int is_read,usize_t * nread)588 xd3_amiga_io (BPTR fd, uint8_t *buf, usize_t size,
589 int is_read, usize_t *nread)
590 {
591 usize_t nproc = 0;
592
593 while (nproc < size)
594 {
595 LONG result = (is_read)?
596 Read(fd, buf + nproc, size - nproc) :
597 Write(fd, buf + nproc, size - nproc);
598
599 if (result < 0) return get_errno ();
600
601 if (nread != NULL && result == 0) break;
602
603 nproc += result;
604 }
605 if (nread != NULL) { (*nread) = nproc; }
606 return 0;
607 }
608 #endif
609
610 #if XD3_WIN32
611 static int
xd3_win32_io(HANDLE file,uint8_t * buf,usize_t size,int is_read,usize_t * nread)612 xd3_win32_io (HANDLE file, uint8_t *buf, usize_t size,
613 int is_read, usize_t *nread)
614 {
615 int ret = 0;
616 usize_t nproc = 0;
617
618 while (nproc < size)
619 {
620 DWORD nproc2;
621 if ((is_read ?
622 ReadFile (file, buf + nproc, size - nproc, &nproc2, NULL) :
623 WriteFile (file, buf + nproc, size - nproc, &nproc2, NULL)) == 0)
624 {
625 ret = get_errno();
626 if (ret != ERROR_HANDLE_EOF && ret != ERROR_BROKEN_PIPE)
627 {
628 return ret;
629 }
630 /* By falling through here, we'll break this loop in the
631 * read case in case of eof or broken pipe. */
632 }
633
634 nproc += (usize_t) nproc2;
635
636 if (nread != NULL && nproc2 == 0) { break; }
637 }
638 if (nread != NULL) { (*nread) = nproc; }
639 return 0;
640 }
641 #endif
642
643 /* POSIX is unbuffered, while STDIO is buffered. main_file_read()
644 * should always be called on blocks. */
645 static int
main_file_read(main_file * ifile,uint8_t * buf,usize_t size,usize_t * nread,const char * msg)646 main_file_read (main_file *ifile,
647 uint8_t *buf,
648 usize_t size,
649 usize_t *nread,
650 const char *msg)
651 {
652 int ret = 0;
653
654 #if XD3_STDIO
655 usize_t result;
656
657 result = fread (buf, 1, size, ifile->file);
658
659 if (result < size && ferror (ifile->file))
660 {
661 ret = get_errno ();
662 }
663 else
664 {
665 *nread = result;
666 }
667
668 #elif XD3_POSIX
669 ret = xd3_posix_io (ifile->file, buf, size, (xd3_posix_func*) &read, nread);
670 #elif XD3_WIN32
671 ret = xd3_win32_io (ifile->file, buf, size, 1 /* is_read */, nread);
672 #elif XD3_AMIGA
673 ret = xd3_amiga_io (ifile->file, buf, size, 1 /* is_read */, nread);
674 #endif
675
676 if (ret)
677 {
678 if (use_options->debug_print)
679 use_options->debug_print("%s: %s: %s\n", msg, ifile->filename, xd3_mainerror (ret));
680 }
681 else
682 {
683 ifile->nread += (*nread);
684 }
685
686 return ret;
687 }
688
689 static int
main_file_write(main_file * ofile,uint8_t * buf,usize_t size,const char * msg)690 main_file_write (main_file *ofile, uint8_t *buf, usize_t size, const char *msg)
691 {
692 int ret = 0;
693
694 #if XD3_STDIO
695 usize_t result;
696
697 result = fwrite (buf, 1, size, ofile->file);
698
699 if (result != size) { ret = get_errno (); }
700
701 #elif XD3_POSIX
702 ret = xd3_posix_io (ofile->file, buf, size, (xd3_posix_func*) &write, NULL);
703
704 #elif XD3_WIN32
705 ret = xd3_win32_io (ofile->file, buf, size, 0, NULL);
706
707 #elif XD3_AMIGA
708 ret = xd3_amiga_io (ofile->file, buf, size, 0, NULL);
709
710 #endif
711
712 if (ret)
713 {
714 if (use_options->debug_print)
715 use_options->debug_print("%s: %s: %s\n", msg, ofile->filename, xd3_mainerror (ret));
716 }
717 else
718 {
719 ofile->nwrite += size;
720 if (use_options->progress_data != NULL)
721 {
722 use_options->progress_data->current_file_written += size;
723 use_options->progress_data->current_written += size;
724 if (use_options->progress_log)
725 use_options->progress_log ();
726 }
727 }
728
729 return ret;
730 }
731
732 static int
main_file_seek(main_file * xfile,xoff_t pos)733 main_file_seek (main_file *xfile, xoff_t pos)
734 {
735 int ret = 0;
736
737 #if XD3_STDIO
738 if (fseek (xfile->file, pos, SEEK_SET) != 0) { ret = get_errno (); }
739
740 #elif XD3_POSIX
741 if ((xoff_t) lseek (xfile->file, pos, SEEK_SET) != pos)
742 { ret = get_errno (); }
743
744 #elif XD3_WIN32
745 # if (_WIN32_WINNT >= 0x0500)
746 LARGE_INTEGER move, out;
747 move.QuadPart = pos;
748 if (SetFilePointerEx(xfile->file, move, &out, FILE_BEGIN) == 0)
749 {
750 ret = get_errno ();
751 }
752 # else
753 if (SetFilePointer(xfile->file, (LONG)pos, NULL, FILE_BEGIN) ==
754 INVALID_SET_FILE_POINTER)
755 {
756 ret = get_errno ();
757 }
758 # endif
759
760 #elif XD3_AMIGA
761 if (Seek(xfile->file, pos, OFFSET_BEGINNING) < 0)
762 ret = get_errno ();
763 #endif
764
765 return ret;
766 }
767
768 /* This function simply writes the stream output buffer, if there is
769 * any, for encode, decode and recode commands. (The VCDIFF tools use
770 * main_print_func()). */
771 static int
main_write_output(xd3_stream * stream,main_file * ofile)772 main_write_output (xd3_stream* stream, main_file *ofile)
773 {
774 int ret;
775
776 if (stream->avail_out > 0 &&
777 (ret = main_file_write (ofile, stream->next_out,
778 stream->avail_out, "write failed")))
779 {
780 return ret;
781 }
782
783 return 0;
784 }
785
786 /*********************************************************************
787 Main I/O routines
788 **********************************************************************/
789
790 /* This function acts like the above except it may also try to
791 * recognize a compressed input (source or target) when the first
792 * buffer of data is read. The EXTERNAL_COMPRESSION code is called to
793 * search for magic numbers. */
794 static int
main_read_primary_input(main_file * file,uint8_t * buf,usize_t size,usize_t * nread)795 main_read_primary_input (main_file *file,
796 uint8_t *buf,
797 usize_t size,
798 usize_t *nread)
799 {
800 return main_file_read (file, buf, size, nread, "input read failed");
801 }
802
803 /* Open the main output file, sets a default file name, initiate
804 * recompression. This function is expected to fprint any error
805 * messages. */
806 static int
main_open_output(xd3_stream * stream,main_file * ofile)807 main_open_output (xd3_stream *stream, main_file *ofile)
808 {
809 int ret;
810
811 if ((ret = main_file_open (ofile, ofile->filename, XO_WRITE)))
812 {
813 return ret;
814 }
815
816 if (use_options->verbose && use_options->debug_print)
817 {
818 use_options->debug_print("output %s\n", ofile->filename);
819 }
820
821 return 0;
822 }
823
824 static usize_t
main_get_winsize(main_file * ifile)825 main_get_winsize (main_file *ifile) {
826 xoff_t file_size = 0;
827 usize_t size = use_options->winsize;
828
829 if (main_file_stat (ifile, &file_size) == 0)
830 {
831 size = (usize_t) xd3_min(file_size, (xoff_t) size);
832 }
833
834 size = xd3_max(size, XD3_ALLOCSIZE);
835
836 if (use_options->verbose && use_options->debug_print)
837 {
838 use_options->debug_print("input %s window size %u bytes\n",
839 ifile->filename, size);
840 }
841
842 return size;
843 }
844
845 /*********************************************************************
846 Main routines
847 ********************************************************************/
848
849 /* This is a generic input function. It calls the xd3_encode_input or
850 * xd3_decode_input functions and makes calls to the various input
851 * handling routines above, which coordinate external decompression.
852 */
853 static int
main_input(main_file * ifile,main_file * ofile,main_file * sfile)854 main_input (main_file *ifile,
855 main_file *ofile,
856 main_file *sfile)
857 {
858 int ret;
859 xd3_stream stream;
860 usize_t nread = 0;
861 usize_t winsize;
862 int stream_flags = 0;
863 xd3_config config;
864 xd3_source source;
865
866 memset (& stream, 0, sizeof (stream));
867 memset (& source, 0, sizeof (source));
868 memset (& config, 0, sizeof (config));
869
870 config.alloc = main_alloc;
871 config.freef = main_free1;
872
873 config.iopt_size = use_options->iopt_size;
874 config.sprevsz = use_options->sprevsz;
875
876 if (use_options->use_checksum == 0)
877 {
878 stream_flags |= XD3_ADLER32_NOVER;
879 }
880
881 main_bsize = winsize = main_get_winsize (ifile);
882 if ((main_bdata = (uint8_t*) main_malloc (winsize)) == NULL)
883 {
884 return EXIT_FAILURE;
885 }
886
887 config.winsize = winsize;
888 config.srcwin_maxsz = use_options->srcwinsz;
889 config.getblk = main_getblk_func;
890 config.flags = stream_flags;
891
892 if ((ret = xd3_config_stream (& stream, & config)))
893 {
894 if (use_options->debug_print)
895 use_options->debug_print(XD3_LIB_ERRMSG (& stream, ret));
896 return EXIT_FAILURE;
897 }
898
899 /* Main input loop. */
900 do
901 {
902 xoff_t input_offset;
903 xoff_t input_remain;
904 usize_t try_read;
905
906 input_offset = ifile->nread;
907
908 input_remain = XOFF_T_MAX - input_offset;
909
910 try_read = (usize_t) xd3_min ((xoff_t) config.winsize, input_remain);
911
912 if ((ret = main_read_primary_input (ifile, main_bdata,
913 try_read, & nread)))
914 {
915 return EXIT_FAILURE;
916 }
917
918 /* If we've reached EOF tell the stream to flush. */
919 if (nread < try_read)
920 {
921 stream.flags |= XD3_FLUSH;
922 }
923
924 xd3_avail_input (& stream, main_bdata, nread);
925
926 /* If we read zero bytes after encoding at least one window... */
927 if (nread == 0 && stream.current_window > 0) {
928 break;
929 }
930
931 again:
932 ret = xd3_decode_input (& stream);
933
934 switch (ret)
935 {
936 case XD3_INPUT:
937 continue;
938
939 case XD3_GOTHEADER:
940 {
941 XD3_ASSERT (stream.current_window == 0);
942
943 /* Need to process the appheader as soon as possible. It may
944 * contain a suggested default filename/decompression routine for
945 * the ofile, and it may contain default/decompression routine for
946 * the sources. */
947 /* Now open the source file. */
948 if ((sfile->filename != NULL) &&
949 (ret = main_set_source (& stream, sfile, & source)))
950 {
951 return EXIT_FAILURE;
952 }
953 }
954 /* FALLTHROUGH */
955 case XD3_WINSTART:
956 {
957 /* e.g., set or unset XD3_SKIP_WINDOW. */
958 goto again;
959 }
960
961 case XD3_OUTPUT:
962 {
963 /* Defer opening the output file until the stream produces its
964 * first output for both encoder and decoder, this way we
965 * delay long enough for the decoder to receive the
966 * application header. (Or longer if there are skipped
967 * windows, but I can't think of any reason not to delay
968 * open.) */
969 if (ofile != NULL &&
970 ! main_file_isopen (ofile) &&
971 (ret = main_open_output (& stream, ofile)) != 0)
972 {
973 return EXIT_FAILURE;
974 }
975
976 if ((ret = main_write_output(& stream, ofile)) &&
977 (ret != PRINTHDR_SPECIAL))
978 {
979 return EXIT_FAILURE;
980 }
981
982 if (ret == PRINTHDR_SPECIAL)
983 {
984 xd3_abort_stream (& stream);
985 ret = EXIT_SUCCESS;
986 goto done;
987 }
988
989 ret = 0;
990
991 xd3_consume_output (& stream);
992 goto again;
993 }
994
995 case XD3_WINFINISH:
996 {
997 goto again;
998 }
999
1000 default:
1001 /* xd3_decode_input() error */
1002 if (use_options->debug_print)
1003 use_options->debug_print(XD3_LIB_ERRMSG (& stream, ret));
1004 return EXIT_FAILURE;
1005 }
1006 }
1007 while (nread == config.winsize);
1008 done:
1009 /* Close the inputs. (ifile must be open, sfile may be open) */
1010 main_file_close (ifile);
1011 if (sfile != NULL)
1012 {
1013 main_file_close (sfile);
1014 }
1015
1016 /* If output file is not open yet because of delayed-open, it means
1017 * we never encountered a window in the delta, but it could have had
1018 * a VCDIFF header? TODO: solve this elsewhere. For now, it prints
1019 * "nothing to output" below, but the check doesn't happen in case
1020 * of option_no_output. */
1021 if (ofile != NULL)
1022 {
1023 if (! main_file_isopen (ofile))
1024 {
1025 if (use_options->debug_print)
1026 use_options->debug_print("nothing to output: %s\n", ifile->filename);
1027 return EXIT_FAILURE;
1028 }
1029
1030 /* Have to close the output before calling
1031 * main_external_compression_finish, or else it hangs. */
1032 if (main_file_close (ofile) != 0)
1033 {
1034 return EXIT_FAILURE;
1035 }
1036 }
1037
1038 if ((ret = xd3_close_stream (& stream)))
1039 {
1040 if (use_options->debug_print)
1041 use_options->debug_print(XD3_LIB_ERRMSG (& stream, ret));
1042 return EXIT_FAILURE;
1043 }
1044
1045 xd3_free_stream (& stream);
1046
1047 return EXIT_SUCCESS;
1048 }
1049
1050 /* free memory before exit, reset single-use variables. */
1051 static void
main_cleanup(void)1052 main_cleanup (void)
1053 {
1054 main_free (main_bdata);
1055 main_bdata = NULL;
1056 main_bsize = 0;
1057
1058 main_lru_cleanup();
1059
1060 XD3_ASSERT (main_mallocs == 0);
1061 }
1062
1063 int
xd3_main_patcher(xd3_options_t * options,const char * srcfile,const char * deltafile,const char * outfile)1064 xd3_main_patcher (xd3_options_t *options,
1065 const char *srcfile,
1066 const char *deltafile,
1067 const char *outfile)
1068 {
1069 main_file ifile;
1070 main_file ofile;
1071 main_file sfile;
1072 int ret;
1073
1074 XD3_ASSERT (srcfile != NULL);
1075 XD3_ASSERT (deltafile != NULL);
1076 XD3_ASSERT (outfile != NULL);
1077
1078 main_file_init (& ifile);
1079 main_file_init (& ofile);
1080 main_file_init (& sfile);
1081
1082 reset_defaults();
1083 if (options != NULL)
1084 use_options = options;
1085
1086 sfile.filename = srcfile;
1087 ofile.filename = outfile;
1088 ifile.filename = deltafile;
1089
1090 if ((ret = main_file_open (& ifile, ifile.filename, XO_READ)))
1091 {
1092 ret = EXIT_FAILURE;
1093 goto cleanup;
1094 }
1095
1096 ret = main_input (& ifile, & ofile, & sfile);
1097
1098 cleanup:
1099 main_file_cleanup (& ifile);
1100 main_file_cleanup (& ofile);
1101 main_file_cleanup (& sfile);
1102
1103 main_cleanup ();
1104
1105 fflush (stdout);
1106 fflush (stderr);
1107 return ret;
1108 }
1109
1110 #define READ_BUFSIZE 8192 /* BUFSIZ */
1111 unsigned long
xd3_calc_adler32(const char * srcfile)1112 xd3_calc_adler32 (const char *srcfile)
1113 {
1114 main_file ifile;
1115 unsigned long sum;
1116 uint8_t buf[READ_BUFSIZE];
1117 usize_t nread;
1118
1119 XD3_ASSERT (srcfile != NULL);
1120
1121 main_file_init (& ifile);
1122 ifile.filename = srcfile;
1123 if (main_file_open (& ifile, ifile.filename, XO_READ) != 0)
1124 return 1UL;
1125
1126 nread = READ_BUFSIZE;
1127 sum = 1UL;
1128 while (nread == READ_BUFSIZE) /* otherwise: short read == EOF */
1129 {
1130 if (main_read_primary_input (&ifile, buf, READ_BUFSIZE, & nread)
1131 != 0)
1132 {
1133 sum = 1UL;
1134 break;
1135 }
1136
1137 if (nread != 0)
1138 sum = adler32 (sum, buf, nread);
1139 }
1140
1141 main_file_cleanup (& ifile);
1142 return sum;
1143 }
1144