2 * libdpkg - Debian packaging suite library routines
3 * buffer.c - buffer I/O handling routines
5 * Copyright © 1999, 2000 Wichert Akkerman <wakkerma@debian.org>
6 * Copyright © 2000-2003 Adam Heath <doogie@debian.org>
7 * Copyright © 2008-2012 Guillem Jover <guillem@debian.org>
9 * This is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
26 #include <sys/types.h>
34 #include <dpkg/i18n.h>
35 #include <dpkg/dpkg.h>
36 #include <dpkg/varbuf.h>
37 #include <dpkg/fdio.h>
38 #include <dpkg/buffer.h>
40 struct buffer_md5_ctx
{
46 buffer_md5_init(struct buffer_data
*data
)
48 struct buffer_md5_ctx
*ctx
;
50 ctx
= m_malloc(sizeof(*ctx
));
51 ctx
->hash
= data
->arg
.ptr
;
57 buffer_digest_init(struct buffer_data
*data
)
60 case BUFFER_DIGEST_NULL
:
62 case BUFFER_DIGEST_MD5
:
63 buffer_md5_init(data
);
70 buffer_digest_update(struct buffer_data
*digest
, const void *buf
, off_t length
)
74 switch (digest
->type
) {
75 case BUFFER_DIGEST_NULL
:
77 case BUFFER_DIGEST_MD5
:
78 MD5Update(&(((struct buffer_md5_ctx
*)digest
->arg
.ptr
)->ctx
),
82 internerr("unknown data type %i", digest
->type
);
89 buffer_md5_done(struct buffer_data
*data
)
91 struct buffer_md5_ctx
*ctx
;
92 unsigned char digest
[16], *p
= digest
;
96 ctx
= (struct buffer_md5_ctx
*)data
->arg
.ptr
;
98 MD5Final(digest
, &ctx
->ctx
);
99 for (i
= 0; i
< 16; ++i
) {
100 sprintf(hash
, "%02x", *p
++);
108 buffer_digest_done(struct buffer_data
*data
)
110 switch (data
->type
) {
111 case BUFFER_DIGEST_NULL
:
113 case BUFFER_DIGEST_MD5
:
114 buffer_md5_done(data
);
121 buffer_write(struct buffer_data
*data
, const void *buf
, off_t length
,
122 struct dpkg_error
*err
)
126 switch (data
->type
) {
127 case BUFFER_WRITE_VBUF
:
128 varbuf_add_buf((struct varbuf
*)data
->arg
.ptr
, buf
, length
);
130 case BUFFER_WRITE_FD
:
131 ret
= fd_write(data
->arg
.i
, buf
, length
);
133 dpkg_put_errno(err
, _("failed to write"));
135 case BUFFER_WRITE_NULL
:
138 internerr("unknown data type %i", data
->type
);
145 buffer_read(struct buffer_data
*data
, void *buf
, off_t length
,
146 struct dpkg_error
*err
)
150 switch (data
->type
) {
152 ret
= fd_read(data
->arg
.i
, buf
, length
);
154 dpkg_put_errno(err
, _("failed to read"));
157 internerr("unknown data type %i", data
->type
);
164 buffer_digest(const void *input
, void *output
, int type
, off_t limit
)
166 struct buffer_data data
= { .arg
.ptr
= output
, .type
= type
};
169 buffer_digest_init(&data
);
170 ret
= buffer_digest_update(&data
, input
, limit
);
171 buffer_digest_done(&data
);
177 buffer_copy(struct buffer_data
*read_data
,
178 struct buffer_data
*digest
,
179 struct buffer_data
*write_data
,
180 off_t limit
, struct dpkg_error
*err
)
183 int bufsize
= DPKG_BUFFER_SIZE
;
184 off_t bytesread
= 0, byteswritten
= 0;
185 off_t totalread
= 0, totalwritten
= 0;
187 if ((limit
!= -1) && (limit
< bufsize
))
192 buf
= m_malloc(bufsize
);
194 buffer_digest_init(digest
);
196 while (bufsize
> 0) {
197 bytesread
= buffer_read(read_data
, buf
, bufsize
, err
);
203 totalread
+= bytesread
;
211 buffer_digest_update(digest
, buf
, bytesread
);
213 byteswritten
= buffer_write(write_data
, buf
, bytesread
, err
);
214 if (byteswritten
< 0)
216 if (byteswritten
== 0)
219 totalwritten
+= byteswritten
;
222 buffer_digest_done(digest
);
226 if (bytesread
< 0 || byteswritten
< 0)
228 if (totalread
!= totalwritten
)
231 return dpkg_put_error(err
, _("unexpected end of file or stream"));
237 buffer_copy_IntInt(int Iin
, int Tin
,
238 void *Pdigest
, int Tdigest
,
240 off_t limit
, struct dpkg_error
*err
)
242 struct buffer_data read_data
= { .type
= Tin
, .arg
.i
= Iin
};
243 struct buffer_data digest
= { .type
= Tdigest
, .arg
.ptr
= Pdigest
};
244 struct buffer_data write_data
= { .type
= Tout
, .arg
.i
= Iout
};
246 return buffer_copy(&read_data
, &digest
, &write_data
, limit
, err
);
250 buffer_copy_IntPtr(int Iin
, int Tin
,
251 void *Pdigest
, int Tdigest
,
252 void *Pout
, int Tout
,
253 off_t limit
, struct dpkg_error
*err
)
255 struct buffer_data read_data
= { .type
= Tin
, .arg
.i
= Iin
};
256 struct buffer_data digest
= { .type
= Tdigest
, .arg
.ptr
= Pdigest
};
257 struct buffer_data write_data
= { .type
= Tout
, .arg
.ptr
= Pout
};
259 return buffer_copy(&read_data
, &digest
, &write_data
, limit
, err
);
263 buffer_skip(struct buffer_data
*input
, off_t limit
, struct dpkg_error
*err
)
265 struct buffer_data output
;
266 struct buffer_data digest
;
268 switch (input
->type
) {
270 if (lseek(input
->arg
.i
, limit
, SEEK_CUR
) != -1)
273 return dpkg_put_errno(err
, _("failed to seek"));
276 internerr("unknown data type %i", input
->type
);
279 output
.type
= BUFFER_WRITE_NULL
;
280 output
.arg
.ptr
= NULL
;
281 digest
.type
= BUFFER_DIGEST_NULL
;
282 digest
.arg
.ptr
= NULL
;
284 return buffer_copy(input
, &digest
, &output
, limit
, err
);
288 buffer_skip_Int(int I
, int T
, off_t limit
, struct dpkg_error
*err
)
290 struct buffer_data input
= { .type
= T
, .arg
.i
= I
};
292 return buffer_skip(&input
, limit
, err
);