If the attempt to open the archive fails (either the client open

routine fails or the first read fails), invoke the client close
routine immediately so the client can clean up.  Also, don't store the
client pointers in this case, so that the client close routine can't
accidentally get called more than once.

A minor style fix to archive_read_open_fd.c while I'm here.

PR: 86453
Thanks to: Andrew Turner for reporting this and suggesting a fix.
This commit is contained in:
Tim Kientzle 2006-01-17 04:49:04 +00:00
parent bbf3318c61
commit 752ede3058
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=154445
2 changed files with 38 additions and 14 deletions

View file

@ -107,8 +107,8 @@ archive_read_set_bytes_per_block(struct archive *a, int bytes_per_block)
*/
int
archive_read_open(struct archive *a, void *client_data,
archive_open_callback *opener, archive_read_callback *reader,
archive_close_callback *closer)
archive_open_callback *client_opener, archive_read_callback *client_reader,
archive_close_callback *client_closer)
{
const void *buffer;
ssize_t bytes_read;
@ -117,36 +117,59 @@ archive_read_open(struct archive *a, void *client_data,
__archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_open");
if (reader == NULL)
if (client_reader == NULL)
__archive_errx(1,
"No reader function provided to archive_read_open");
a->client_reader = reader;
a->client_opener = opener;
a->client_closer = closer;
a->client_data = client_data;
/*
* Set these NULL initially. If the open or initial read fails,
* we'll leave them NULL to indicate that the file is invalid.
* (In particular, this helps ensure that the closer doesn't
* get called more than once.)
*/
a->client_opener = NULL;
a->client_reader = NULL;
a->client_closer = NULL;
a->client_data = NULL;
/* Open data source. */
if (a->client_opener != NULL) {
e =(a->client_opener)(a, a->client_data);
if (e != 0)
if (client_opener != NULL) {
e =(client_opener)(a, client_data);
if (e != 0) {
/* If the open failed, call the closer to clean up. */
if (client_closer)
(client_closer)(a, client_data);
return (e);
}
}
/* Read first block now for format detection. */
bytes_read = (a->client_reader)(a, a->client_data, &buffer);
bytes_read = (client_reader)(a, client_data, &buffer);
/* client_reader should have already set error information. */
if (bytes_read < 0)
if (bytes_read < 0) {
/* If the first read fails, close before returning error. */
if (client_closer)
(client_closer)(a, client_data);
/* client_reader should have already set error information. */
return (ARCHIVE_FATAL);
}
/* An empty archive is a serious error. */
if (bytes_read == 0) {
archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
"Empty input file");
/* Close the empty file. */
if (client_closer)
(client_closer)(a, client_data);
return (ARCHIVE_FATAL);
}
/* Now that the client callbacks have worked, remember them. */
a->client_opener = client_opener; /* Do we need to remember this? */
a->client_reader = client_reader;
a->client_closer = client_closer;
a->client_data = client_data;
/* Select a decompression routine. */
high_bidder = choose_decompressor(a, buffer, bytes_read);
if (high_bidder < 0)

View file

@ -99,7 +99,8 @@ file_close(struct archive *a, void *client_data)
struct read_fd_data *mine = client_data;
(void)a; /* UNUSED */
free(mine->buffer);
if (mine->buffer != NULL)
free(mine->buffer);
free(mine);
return (ARCHIVE_OK);
}