struct read_fd_data {
int fd;
size_t block_size;
+ int64_t size;
char use_lseek;
void *buffer;
};
if (S_ISREG(st.st_mode)) {
archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);
mine->use_lseek = 1;
+ mine->size = st.st_size;
}
#if defined(__CYGWIN__) || defined(_WIN32)
setmode(mine->fd, O_BINARY);
if (skip == 0)
return (0);
- if (((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0) &&
- ((new_offset = lseek(mine->fd, skip, SEEK_CUR)) >= 0))
- return (new_offset - old_offset);
+ if ((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0) {
+ if (old_offset >= mine->size ||
+ skip > mine->size - old_offset) {
+ /* Do not seek past end of file. */
+ errno = ESPIPE;
+ } else if ((new_offset = lseek(mine->fd, skip, SEEK_CUR)) >= 0)
+ return (new_offset - old_offset);
+ }
/* If seek failed once, it will probably fail again. */
mine->use_lseek = 0;
struct read_FILE_data {
FILE *f;
size_t block_size;
+ int64_t size;
void *buffer;
char can_skip;
};
archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);
/* Enable the seek optimization only for regular files. */
mine->can_skip = 1;
+ mine->size = st.st_size;
}
#if defined(__CYGWIN__) || defined(_WIN32)
#else
long skip = (long)request;
#endif
+ int64_t old_offset, new_offset;
int skip_bits = sizeof(skip) * 8 - 1;
(void)a; /* UNUSED */
#ifdef __ANDROID__
/* fileno() isn't safe on all platforms ... see above. */
- if (lseek(fileno(mine->f), skip, SEEK_CUR) < 0)
+ old_offset = lseek(fileno(mine->f), 0, SEEK_CUR);
#elif HAVE__FSEEKI64
- if (_fseeki64(mine->f, skip, SEEK_CUR) != 0)
+ old_offset = _ftelli64(mine->f);
#elif HAVE_FSEEKO
- if (fseeko(mine->f, skip, SEEK_CUR) != 0)
+ old_offset = ftello(mine->f);
#else
- if (fseek(mine->f, skip, SEEK_CUR) != 0)
+ old_offset = ftell(mine->f);
#endif
- {
- mine->can_skip = 0;
- return (0);
+ if (old_offset >= 0) {
+ if (old_offset < mine->size &&
+ skip <= mine->size - old_offset) {
+#ifdef __ANDROID__
+ new_offset = lseek(fileno(mine->f), skip, SEEK_CUR);
+#elif HAVE__FSEEKI64
+ new_offset = _fseeki64(mine->f, skip, SEEK_CUR);
+#elif HAVE_FSEEKO
+ new_offset = fseeko(mine->f, skip, SEEK_CUR);
+#else
+ new_offset = fseek(mine->f, skip, SEEK_CUR);
+#endif
+ if (new_offset >= 0)
+ return (new_offset - old_offset);
+ }
}
- return (request);
+
+ mine->can_skip = 0;
+ return (0);
}
/*
size_t block_size;
void *buffer;
mode_t st_mode; /* Mode bits for opened file. */
+ int64_t size;
char use_lseek;
enum fnt_e { FNT_STDIN, FNT_MBS, FNT_WCS } filename_type;
union {
mine->st_mode = st.st_mode;
/* Disk-like inputs can use lseek(). */
- if (is_disk_like)
+ if (is_disk_like) {
mine->use_lseek = 1;
+ mine->size = st.st_size;
+ }
return (ARCHIVE_OK);
fail:
skip = max_skip;
}
- if ((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0 &&
- (new_offset = lseek(mine->fd, skip, SEEK_CUR)) >= 0)
- return (new_offset - old_offset);
+ if ((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0) {
+ if (old_offset >= mine->size ||
+ skip > mine->size - old_offset) {
+ /* Do not seek past end of file. */
+ errno = ESPIPE;
+ } else if ((new_offset = lseek(mine->fd, skip, SEEK_CUR)) >= 0)
+ return (new_offset - old_offset);
+ }
/* If lseek() fails, don't bother trying again. */
mine->use_lseek = 0;
assertA(ARCHIVE_OK == archive_read_next_header(a, &ae));
assertA(archive_read_data(a, buf, sizeof(buf)) <= 0);
- /* Test EOF */
- assertA(1 == archive_read_next_header(a, &ae));
+ /* Test for truncation */
+ assertA(ARCHIVE_FATAL == archive_read_next_header(a, &ae));
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
assertA(archive_read_data(a, buf, sizeof(buf)) <= 0);
/* Test EOF */
- assertA(1 == archive_read_next_header(a, &ae));
+ assertA(ARCHIVE_FATAL == archive_read_next_header(a, &ae));
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));