summaryrefslogtreecommitdiff
path: root/xdelta3
diff options
context:
space:
mode:
Diffstat (limited to 'xdelta3')
-rw-r--r--xdelta3/Makefile2
-rw-r--r--xdelta3/xdelta3-main.h255
-rw-r--r--xdelta3/xdelta3.c12
3 files changed, 158 insertions, 111 deletions
diff --git a/xdelta3/Makefile b/xdelta3/Makefile
index e44ffd9..02c610e 100644
--- a/xdelta3/Makefile
+++ b/xdelta3/Makefile
@@ -170,7 +170,7 @@ xdelta3-32: $(SOURCES)
170xdelta3-debug2: $(SOURCES) 170xdelta3-debug2: $(SOURCES)
171 $(CC) -g $(CFLAGS) \ 171 $(CC) -g $(CFLAGS) \
172 xdelta3.c -o xdelta3-debug2 \ 172 xdelta3.c -o xdelta3-debug2 \
173 -DXD3_DEBUG=3 \ 173 -DXD3_DEBUG=2 \
174 -DXD3_MAIN=1 \ 174 -DXD3_MAIN=1 \
175 -DXD3_POSIX=1 \ 175 -DXD3_POSIX=1 \
176 -DXD3_USE_LARGEFILE64=1 \ 176 -DXD3_USE_LARGEFILE64=1 \
diff --git a/xdelta3/xdelta3-main.h b/xdelta3/xdelta3-main.h
index 7fa0901..b33b26a 100644
--- a/xdelta3/xdelta3-main.h
+++ b/xdelta3/xdelta3-main.h
@@ -339,7 +339,7 @@ static usize_t lru_size = 0;
339static main_blklru *lru = NULL; /* array of lru_size elts */ 339static main_blklru *lru = NULL; /* array of lru_size elts */
340static main_blklru_list lru_list; 340static main_blklru_list lru_list;
341static main_blklru_list lru_free; 341static main_blklru_list lru_free;
342static int do_not_lru = 0; /* set to avoid lru */ 342static int do_src_fifo = 0; /* set to avoid lru */
343 343
344static int lru_hits = 0; 344static int lru_hits = 0;
345static int lru_misses = 0; 345static int lru_misses = 0;
@@ -452,7 +452,7 @@ reset_defaults(void)
452 main_bsize = 0; 452 main_bsize = 0;
453 lru_size = 0; 453 lru_size = 0;
454 lru = NULL; 454 lru = NULL;
455 do_not_lru = 0; 455 do_src_fifo = 0;
456 lru_hits = 0; 456 lru_hits = 0;
457 lru_misses = 0; 457 lru_misses = 0;
458 lru_filled = 0; 458 lru_filled = 0;
@@ -1032,7 +1032,7 @@ main_file_read (main_file *ifile,
1032 } 1032 }
1033 else 1033 else
1034 { 1034 {
1035 if (option_verbose > 3) { XPR(NT "read %s: %u bytes\n", 1035 if (option_verbose > 4) { XPR(NT "read %s: %u bytes\n",
1036 ifile->filename, (*nread)); } 1036 ifile->filename, (*nread)); }
1037 ifile->nread += (*nread); 1037 ifile->nread += (*nread);
1038 } 1038 }
@@ -1923,7 +1923,8 @@ main_merge_output (xd3_stream *stream, main_file *ofile)
1923 (stream->dec_win_ind & VCD_ADLER32) != 0) 1923 (stream->dec_win_ind & VCD_ADLER32) != 0)
1924 { 1924 {
1925 recode_stream->flags |= XD3_ADLER32_RECODE; 1925 recode_stream->flags |= XD3_ADLER32_RECODE;
1926 recode_stream->recode_adler32 = stream->whole_target.wininfo[window_num].adler32; 1926 recode_stream->recode_adler32 =
1927 stream->whole_target.wininfo[window_num].adler32;
1927 } 1928 }
1928 1929
1929 window_num++; 1930 window_num++;
@@ -2880,11 +2881,18 @@ main_set_source (xd3_stream *stream, xd3_cmd cmd,
2880 * size_known can still change (due to secondary 2881 * size_known can still change (due to secondary
2881 * decompression). Calls main_decompress_input_check() via 2882 * decompression). Calls main_decompress_input_check() via
2882 * main_read_primary_input(). */ 2883 * main_read_primary_input(). */
2884 /* TODO(jmacd): This is a huge hack! Fix me. */
2883 lru_size = 1; 2885 lru_size = 1;
2884 lru = &block0; 2886 lru = &block0;
2887 XD3_ASSERT (main_blklru_list_empty (& lru_free));
2888 XD3_ASSERT (main_blklru_list_empty (& lru_list));
2885 main_blklru_list_push_back (& lru_free, & lru[0]); 2889 main_blklru_list_push_back (& lru_free, & lru[0]);
2886 ret = main_getblk_func (stream, source, 0); 2890 ret = main_getblk_func (stream, source, 0);
2887 main_blklru_list_remove (& lru[0]); 2891 main_blklru_list_remove (& lru[0]);
2892 /* TODO(jmacd): In particular, not sure if these assertions
2893 * are valid when ret != 0. */
2894 XD3_ASSERT (main_blklru_list_empty (& lru_free));
2895 XD3_ASSERT (main_blklru_list_empty (& lru_list));
2888 lru = NULL; 2896 lru = NULL;
2889 2897
2890 if (ret != 0) 2898 if (ret != 0)
@@ -2923,7 +2931,8 @@ main_set_source (xd3_stream *stream, xd3_cmd cmd,
2923 2931
2924 XD3_ASSERT (lru_size >= 1); 2932 XD3_ASSERT (lru_size >= 1);
2925 2933
2926 if ((lru = (main_blklru*) main_malloc (lru_size * sizeof (main_blklru))) == NULL) 2934 if ((lru = (main_blklru*) main_malloc (lru_size * sizeof (main_blklru)))
2935 == NULL)
2927 { 2936 {
2928 ret = ENOMEM; 2937 ret = ENOMEM;
2929 return ret; 2938 return ret;
@@ -2935,9 +2944,9 @@ main_set_source (xd3_stream *stream, xd3_cmd cmd,
2935 2944
2936 if (! sfile->size_known) 2945 if (! sfile->size_known)
2937 { 2946 {
2938 do_not_lru = 1; 2947 do_src_fifo = 1;
2939 } 2948 }
2940 else if (! do_not_lru) 2949 else if (! do_src_fifo)
2941 { 2950 {
2942 main_blklru_list_push_back (& lru_list, & lru[0]); 2951 main_blklru_list_push_back (& lru_list, & lru[0]);
2943 } 2952 }
@@ -2952,7 +2961,7 @@ main_set_source (xd3_stream *stream, xd3_cmd cmd,
2952 return ret; 2961 return ret;
2953 } 2962 }
2954 2963
2955 if (do_not_lru == 0) 2964 if (! do_src_fifo)
2956 { 2965 {
2957 main_blklru_list_push_back (& lru_free, & lru[i]); 2966 main_blklru_list_push_back (& lru_free, & lru[i]);
2958 } 2967 }
@@ -3008,7 +3017,7 @@ main_set_source (xd3_stream *stream, xd3_cmd cmd,
3008 main_format_bcnt (blksize, blkszbuf), 3017 main_format_bcnt (blksize, blkszbuf),
3009 main_format_bcnt (option_srcwinsz, winszbuf), 3018 main_format_bcnt (option_srcwinsz, winszbuf),
3010 nbufs, 3019 nbufs,
3011 do_not_lru ? " (FIFO)" : ""); 3020 do_src_fifo ? " (FIFO)" : "");
3012 } 3021 }
3013 3022
3014 return 0; 3023 return 0;
@@ -3042,14 +3051,15 @@ main_get_winsize (main_file *ifile) {
3042 *******************************************************************/ 3051 *******************************************************************/
3043 3052
3044static int 3053static int
3045main_getblk_lru (xd3_source *source, xoff_t blkno, main_blklru** blrup, int *is_new) 3054main_getblk_lru (xd3_source *source, xoff_t blkno,
3055 main_blklru** blrup, int *is_new)
3046{ 3056{
3047 main_blklru *blru = NULL; 3057 main_blklru *blru = NULL;
3048 usize_t i; 3058 usize_t i;
3049 3059
3050 (*is_new) = 0; 3060 (*is_new) = 0;
3051 3061
3052 if (do_not_lru) 3062 if (do_src_fifo)
3053 { 3063 {
3054 /* Direct lookup assumes sequential scan w/o skipping blocks. */ 3064 /* Direct lookup assumes sequential scan w/o skipping blocks. */
3055 int idx = blkno % lru_size; 3065 int idx = blkno % lru_size;
@@ -3082,7 +3092,7 @@ main_getblk_lru (xd3_source *source, xoff_t blkno, main_blklru** blrup, int *is_
3082 } 3092 }
3083 } 3093 }
3084 3094
3085 if (do_not_lru) 3095 if (do_src_fifo)
3086 { 3096 {
3087 int idx = blkno % lru_size; 3097 int idx = blkno % lru_size;
3088 blru = & lru[idx]; 3098 blru = & lru[idx];
@@ -3096,6 +3106,7 @@ main_getblk_lru (xd3_source *source, xoff_t blkno, main_blklru** blrup, int *is_
3096 } 3106 }
3097 else 3107 else
3098 { 3108 {
3109 XD3_ASSERT (! main_blklru_list_empty (& lru_list));
3099 blru = main_blklru_list_pop_front (& lru_list); 3110 blru = main_blklru_list_pop_front (& lru_list);
3100 main_blklru_list_push_back (& lru_list, blru); 3111 main_blklru_list_push_back (& lru_list, blru);
3101 } 3112 }
@@ -3108,6 +3119,110 @@ main_getblk_lru (xd3_source *source, xoff_t blkno, main_blklru** blrup, int *is_
3108 return 0; 3119 return 0;
3109} 3120}
3110 3121
3122static int
3123main_read_seek_source (xd3_stream *stream,
3124 xd3_source *source,
3125 xoff_t blkno) {
3126 xoff_t pos = blkno * source->blksize;
3127 main_file *sfile = (main_file*) source->ioh;
3128 main_blklru *blru;
3129 int is_new;
3130 usize_t nread = 0;
3131 int ret = 0;
3132
3133 if (!sfile->seek_failed)
3134 {
3135 ret = main_file_seek (sfile, pos);
3136
3137 if (ret == 0)
3138 {
3139 sfile->source_position = pos;
3140 }
3141 }
3142
3143 /* There's a chance here, that an genuine lseek error will cause
3144 * xdelta3 to shift into non-seekable mode, entering a degraded
3145 * condition. */
3146 if (sfile->seek_failed || ret != 0)
3147 {
3148 /* For an unseekable file (or other seek error, does it
3149 * matter?) */
3150 if (sfile->source_position > pos)
3151 {
3152 /* Could assert !IS_ENCODE(), this shouldn't happen
3153 * because of do_src_fifo during encode. */
3154 if (option_verbose)
3155 {
3156 XPR(NT "source can't seek backwards; requested block offset "
3157 "%"Q"u source position is %"Q"u\n",
3158 pos, sfile->source_position);
3159 }
3160
3161 sfile->seek_failed = 1;
3162 stream->msg = "non-seekable source: "
3163 "copy is too far back (try raising -B)";
3164 return XD3_TOOFARBACK;
3165 }
3166
3167 if (option_verbose > 2 || (option_verbose > 1 && !sfile->seek_failed))
3168 {
3169 XPR(NT "non-seekable source skipping %"Q"u bytes @ %"Q"u\n",
3170 pos - sfile->source_position,
3171 sfile->source_position);
3172 }
3173
3174 sfile->seek_failed = 1;
3175
3176 while (sfile->source_position < pos)
3177 {
3178 xoff_t skip_blkno;
3179 usize_t skip_offset;
3180
3181 xd3_blksize_div (sfile->source_position, source,
3182 &skip_blkno, &skip_offset);
3183
3184 /* Read past unused data */
3185 XD3_ASSERT (pos - sfile->source_position >= source->blksize);
3186 XD3_ASSERT (skip_offset == 0);
3187
3188 if ((ret = main_getblk_lru (source, skip_blkno,
3189 & blru, & is_new)))
3190 {
3191 return ret;
3192 }
3193
3194 XD3_ASSERT (is_new);
3195
3196 if ((ret = main_read_primary_input (sfile,
3197 (uint8_t*) blru->blk,
3198 source->blksize,
3199 & nread,
3200 1 /* source */)))
3201 {
3202 return ret;
3203 }
3204
3205 if (nread != source->blksize)
3206 {
3207 IF_DEBUG1 (DP(RINT "[getblk] short skip block nread = %u\n",
3208 nread));
3209 stream->msg = "non-seekable input is short";
3210 return XD3_INVALID_INPUT;
3211 }
3212
3213 sfile->source_position += nread;
3214 blru->size = nread;
3215
3216 IF_DEBUG1 (DP(RINT "[getblk] skip blkno %"Q"u {%"Q"u} size %u\n",
3217 skip_blkno, blru->blkno, blru->size));
3218
3219 XD3_ASSERT (sfile->source_position <= pos);
3220 }
3221 }
3222
3223 return 0;
3224}
3225
3111/* This is the callback for reading a block of source. This function 3226/* This is the callback for reading a block of source. This function
3112 * is blocking and it implements a small LRU. 3227 * is blocking and it implements a small LRU.
3113 * 3228 *
@@ -3126,6 +3241,7 @@ main_getblk_func (xd3_stream *stream,
3126 main_file *sfile = (main_file*) source->ioh; 3241 main_file *sfile = (main_file*) source->ioh;
3127 main_blklru *blru; 3242 main_blklru *blru;
3128 int is_new; 3243 int is_new;
3244 int did_seek = 0;
3129 usize_t nread = 0; 3245 usize_t nread = 0;
3130 3246
3131 if (allow_fake_source) 3247 if (allow_fake_source)
@@ -3158,97 +3274,20 @@ main_getblk_func (xd3_stream *stream,
3158 /* Only try to seek when the position is wrong. This means the 3274 /* Only try to seek when the position is wrong. This means the
3159 * decoder will fail when the source buffer is too small, but 3275 * decoder will fail when the source buffer is too small, but
3160 * only when the input is non-seekable. */ 3276 * only when the input is non-seekable. */
3161 if (!sfile->seek_failed) 3277 if ((ret = main_read_seek_source (stream, source, blkno)))
3162 { 3278 {
3163 ret = main_file_seek (sfile, pos); 3279 return ret;
3164
3165 if (ret == 0)
3166 {
3167 sfile->source_position = pos;
3168 }
3169 } 3280 }
3170 3281
3171 /* There's a chance here, that an genuine lseek error will cause 3282 /* Indicates that another call to main_getblk_lru() may be
3172 * xdelta3 to shift into non-seekable mode, entering a degraded 3283 * needed */
3173 * condition. */ 3284 did_seek = 1;
3174 if (sfile->seek_failed || ret != 0)
3175 {
3176 /* For an unseekable file (or other seek error, does it
3177 * matter?) */
3178 if (sfile->source_position > pos)
3179 {
3180 /* Could assert !IS_ENCODE(), this shouldn't happen
3181 * because of do_not_lru during encode. */
3182 if (option_verbose)
3183 {
3184 XPR(NT "source can't seek backwards; requested block offset "
3185 "%"Q"u source position is %"Q"u\n",
3186 pos, sfile->source_position);
3187 }
3188
3189 sfile->seek_failed = 1;
3190 stream->msg = "non-seekable source: "
3191 "copy is too far back (try raising -B)";
3192 return XD3_TOOFARBACK;
3193 }
3194
3195 if (option_verbose > 2 || (option_verbose > 1 && !sfile->seek_failed))
3196 {
3197 XPR(NT "non-seekable source skipping %"Q"u bytes @ %"Q"u\n",
3198 pos - sfile->source_position,
3199 sfile->source_position);
3200 }
3201
3202 sfile->seek_failed = 1;
3203
3204 while (sfile->source_position < pos)
3205 {
3206 xoff_t skip_blkno;
3207 usize_t skip_offset;
3208
3209 xd3_blksize_div (sfile->source_position, source, &skip_blkno, &skip_offset);
3210
3211 /* Read past unused data */
3212 XD3_ASSERT (pos - sfile->source_position >= source->blksize);
3213 XD3_ASSERT (skip_offset == 0);
3214
3215 if ((ret = main_getblk_lru (source, skip_blkno, & blru, & is_new)))
3216 {
3217 return ret;
3218 }
3219
3220 XD3_ASSERT (is_new);
3221
3222 if ((ret = main_read_primary_input (sfile,
3223 (uint8_t*) blru->blk,
3224 source->blksize,
3225 & nread,
3226 1 /* source */)))
3227 {
3228 return ret;
3229 }
3230
3231 if (nread != source->blksize)
3232 {
3233 IF_DEBUG1 (DP(RINT "[getblk] short skip block nread = %u\n", nread));
3234 stream->msg = "non-seekable input is short";
3235 return XD3_INVALID_INPUT;
3236 }
3237
3238 sfile->source_position += nread;
3239 blru->size = nread;
3240
3241 IF_DEBUG1 (DP(RINT "[getblk] skip blkno %"Q"u {%"Q"u} size %u\n",
3242 skip_blkno, blru->blkno, blru->size));
3243
3244 XD3_ASSERT (sfile->source_position <= pos);
3245 }
3246 }
3247 } 3285 }
3248 3286
3249 XD3_ASSERT (sfile->source_position == pos); 3287 XD3_ASSERT (sfile->source_position == pos);
3250 3288
3251 if ((ret = main_getblk_lru (source, blkno, & blru, & is_new))) 3289 if (did_seek &&
3290 (ret = main_getblk_lru (source, blkno, & blru, & is_new)))
3252 { 3291 {
3253 return ret; 3292 return ret;
3254 } 3293 }
@@ -3265,15 +3304,22 @@ main_getblk_func (xd3_stream *stream,
3265 /* Save the last block read, used to handle non-seekable files. */ 3304 /* Save the last block read, used to handle non-seekable files. */
3266 sfile->source_position = pos + nread; 3305 sfile->source_position = pos + nread;
3267 3306
3268 main_blklru_list_push_back (& lru_list, blru);
3269
3270 if (option_verbose > 3) 3307 if (option_verbose > 3)
3271 { 3308 {
3272 if (blru->blkno != (xoff_t)-1) 3309 if (blru->blkno != (xoff_t)-1)
3273 { 3310 {
3274 XPR(NT "source block %"Q"u ejects %"Q"u (lru_hits=%u, " 3311 if (blru->blkno != blkno)
3275 "lru_misses=%u, lru_filled=%u)\n", 3312 {
3276 blkno, blru->blkno, lru_hits, lru_misses, lru_filled); 3313 XPR(NT "source block %"Q"u ejects %"Q"u (lru_hits=%u, "
3314 "lru_misses=%u, lru_filled=%u)\n",
3315 blkno, blru->blkno, lru_hits, lru_misses, lru_filled);
3316 }
3317 else
3318 {
3319 XPR(NT "source block %"Q"u read (lru_hits=%u, "
3320 "lru_misses=%u, lru_filled=%u)\n",
3321 blkno, lru_hits, lru_misses, lru_filled);
3322 }
3277 } 3323 }
3278 else 3324 else
3279 { 3325 {
@@ -3287,7 +3333,8 @@ main_getblk_func (xd3_stream *stream,
3287 source->onblk = nread; 3333 source->onblk = nread;
3288 blru->size = nread; 3334 blru->size = nread;
3289 3335
3290 IF_DEBUG1 (DP(RINT "[main_getblk] blkno %"Q"u onblk %u pos %"Q"u srcpos %"Q"u\n", 3336 IF_DEBUG1 (DP(RINT "[main_getblk] blkno %"Q"u onblk %u pos %"Q"u "
3337 "srcpos %"Q"u\n",
3291 blkno, nread, pos, sfile->source_position)); 3338 blkno, nread, pos, sfile->source_position));
3292 3339
3293 return 0; 3340 return 0;
@@ -3331,7 +3378,7 @@ main_input (xd3_cmd cmd,
3331 config.iopt_size = option_iopt_size; 3378 config.iopt_size = option_iopt_size;
3332 config.sprevsz = option_sprevsz; 3379 config.sprevsz = option_sprevsz;
3333 3380
3334 do_not_lru = 0; 3381 do_src_fifo = 0;
3335 3382
3336 start_time = get_millisecs_now (); 3383 start_time = get_millisecs_now ();
3337 3384
@@ -3371,7 +3418,7 @@ main_input (xd3_cmd cmd,
3371 3418
3372#if XD3_ENCODER 3419#if XD3_ENCODER
3373 case CMD_ENCODE: 3420 case CMD_ENCODE:
3374 do_not_lru = 1; 3421 do_src_fifo = 1;
3375 input_func = xd3_encode_input; 3422 input_func = xd3_encode_input;
3376 output_func = main_write_output; 3423 output_func = main_write_output;
3377 3424
diff --git a/xdelta3/xdelta3.c b/xdelta3/xdelta3.c
index 20bffdb..4f91318 100644
--- a/xdelta3/xdelta3.c
+++ b/xdelta3/xdelta3.c
@@ -3798,7 +3798,8 @@ xd3_encode_input (xd3_stream *stream)
3798 3798
3799 case ENC_SEARCH: 3799 case ENC_SEARCH:
3800 IF_DEBUG2 (DP(RINT "[SEARCH] match_state %d avail_in %u %s\n", 3800 IF_DEBUG2 (DP(RINT "[SEARCH] match_state %d avail_in %u %s\n",
3801 stream->match_state, stream->avail_in, stream->src ? "source" : "no source")); 3801 stream->match_state, stream->avail_in,
3802 stream->src ? "source" : "no source"));
3802 3803
3803 /* Reentrant matching. */ 3804 /* Reentrant matching. */
3804 if (stream->src != NULL) 3805 if (stream->src != NULL)
@@ -4368,14 +4369,13 @@ xd3_source_match_setup (xd3_stream *stream, xoff_t srcpos)
4368 /* Implement srcwin_maxsz, which prevents the encoder from seeking 4369 /* Implement srcwin_maxsz, which prevents the encoder from seeking
4369 * back further than the LRU cache maintaining FIFO discipline, (to 4370 * back further than the LRU cache maintaining FIFO discipline, (to
4370 * avoid seeking). */ 4371 * avoid seeking). */
4371 frontier_pos = stream->src->eof_known ? 4372 frontier_pos =
4372 xd3_source_eof (stream->src) : 4373 stream->src->frontier_blkno * stream->src->blksize;
4373 (stream->src->frontier_blkno * stream->src->blksize);
4374 IF_DEBUG1(DP(RINT "[match_setup] frontier_pos %"Q"u, srcpos %"Q"u, " 4374 IF_DEBUG1(DP(RINT "[match_setup] frontier_pos %"Q"u, srcpos %"Q"u, "
4375 "srcwin_maxsz %u\n", 4375 "srcwin_maxsz %u\n",
4376 frontier_pos, srcpos, stream->srcwin_maxsz)); 4376 frontier_pos, srcpos, stream->srcwin_maxsz));
4377 XD3_ASSERT (frontier_pos >= srcpos); 4377 if (srcpos < frontier_pos &&
4378 if (frontier_pos - srcpos > stream->srcwin_maxsz) { 4378 frontier_pos - srcpos > stream->srcwin_maxsz) {
4379 IF_DEBUG1(DP(RINT "[match_setup] rejected due to srcwin_maxsz " 4379 IF_DEBUG1(DP(RINT "[match_setup] rejected due to srcwin_maxsz "
4380 "distance eof=%"Q"u srcpos=%"Q"u maxsz=%u\n", 4380 "distance eof=%"Q"u srcpos=%"Q"u maxsz=%u\n",
4381 xd3_source_eof (stream->src), 4381 xd3_source_eof (stream->src),