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