Skip to content

Commit 5f8f651

Browse files
authored
Merge pull request libarchive#3128 from stoeckmann/into_fd
Improve `archive_read_data_into_fd` with sparse files
2 parents d9279e4 + 7e246b0 commit 5f8f651

1 file changed

Lines changed: 32 additions & 14 deletions

File tree

libarchive/archive_read_data_into_fd.c

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -46,26 +46,36 @@
4646
*/
4747
static int
4848
pad_to(struct archive *a, int fd, int can_lseek,
49-
size_t nulls_size, const char *nulls,
50-
int64_t target_offset, int64_t actual_offset)
49+
char **nulls, int64_t target_offset, int64_t actual_offset)
5150
{
51+
const size_t nulls_size = 16384;
5252
size_t to_write;
5353
ssize_t bytes_written;
5454

5555
if (can_lseek) {
5656
actual_offset = lseek(fd,
5757
target_offset - actual_offset, SEEK_CUR);
5858
if (actual_offset != target_offset) {
59-
archive_set_error(a, errno, "Seek error");
59+
archive_set_error(a,
60+
actual_offset == -1 ? errno : ARCHIVE_ERRNO_MISC,
61+
"Seek error");
6062
return (ARCHIVE_FATAL);
6163
}
6264
return (ARCHIVE_OK);
6365
}
66+
if (*nulls == NULL) {
67+
*nulls = calloc(1, nulls_size);
68+
if (*nulls == NULL) {
69+
archive_set_error(a, errno, "Out of memory");
70+
return (ARCHIVE_FATAL);
71+
}
72+
}
73+
6474
while (target_offset > actual_offset) {
6575
to_write = nulls_size;
6676
if (target_offset < actual_offset + (int64_t)nulls_size)
6777
to_write = (size_t)(target_offset - actual_offset);
68-
bytes_written = write(fd, nulls, to_write);
78+
bytes_written = write(fd, *nulls, to_write);
6979
if (bytes_written < 0) {
7080
archive_set_error(a, errno, "Write error");
7181
return (ARCHIVE_FATAL);
@@ -84,29 +94,27 @@ archive_read_data_into_fd(struct archive *a, int fd)
8494
const void *buff;
8595
size_t size, bytes_to_write;
8696
ssize_t bytes_written;
97+
int64_t fd_offset;
8798
int64_t target_offset;
8899
int64_t actual_offset = 0;
89100
int can_lseek;
90101
char *nulls = NULL;
91-
size_t nulls_size = 16384;
92102

93103
archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA,
94104
"archive_read_data_into_fd");
95105

96106
can_lseek = (fstat(fd, &st) == 0) && S_ISREG(st.st_mode);
97-
if (!can_lseek) {
98-
nulls = calloc(1, nulls_size);
99-
if (!nulls) {
100-
r = ARCHIVE_FATAL;
101-
goto cleanup;
102-
}
107+
if (can_lseek) {
108+
fd_offset = lseek(fd, 0, SEEK_CUR);
109+
if (fd_offset == -1)
110+
can_lseek = 0;
103111
}
104112

105113
while ((r = archive_read_data_block(a, &buff, &size, &target_offset)) ==
106114
ARCHIVE_OK) {
107115
const char *p = buff;
108116
if (target_offset > actual_offset) {
109-
r = pad_to(a, fd, can_lseek, nulls_size, nulls,
117+
r = pad_to(a, fd, can_lseek, &nulls,
110118
target_offset, actual_offset);
111119
if (r != ARCHIVE_OK)
112120
break;
@@ -129,7 +137,7 @@ archive_read_data_into_fd(struct archive *a, int fd)
129137
}
130138

131139
if (r == ARCHIVE_EOF && target_offset > actual_offset) {
132-
r2 = pad_to(a, fd, can_lseek, nulls_size, nulls,
140+
r2 = pad_to(a, fd, can_lseek, &nulls,
133141
target_offset, actual_offset);
134142
if (r2 != ARCHIVE_OK)
135143
r = r2;
@@ -139,5 +147,15 @@ archive_read_data_into_fd(struct archive *a, int fd)
139147
free(nulls);
140148
if (r != ARCHIVE_EOF)
141149
return (r);
142-
return (ARCHIVE_OK);
150+
r = ARCHIVE_OK;
151+
if (can_lseek) {
152+
int64_t offset = lseek(fd, 0, SEEK_CUR);
153+
if (offset - fd_offset != actual_offset) {
154+
archive_set_error(a,
155+
offset == -1 ? errno : ARCHIVE_ERRNO_MISC,
156+
"Seek error");
157+
r = ARCHIVE_FATAL;
158+
}
159+
}
160+
return (r);
143161
}

0 commit comments

Comments
 (0)