summaryrefslogtreecommitdiffstats
path: root/lib/libarchive/archive_read_open_file.c
diff options
context:
space:
mode:
authorkientzle <kientzle@FreeBSD.org>2006-11-24 02:00:48 +0000
committerkientzle <kientzle@FreeBSD.org>2006-11-24 02:00:48 +0000
commit7d9bedda5f3fc686498476685785118426cc9b5c (patch)
tree1718edba490b96d4478714d3358a3b2dfc19fda7 /lib/libarchive/archive_read_open_file.c
parentcceb584eb3c30510c29dc942777634c05bbd9434 (diff)
downloadFreeBSD-src-7d9bedda5f3fc686498476685785118426cc9b5c.zip
FreeBSD-src-7d9bedda5f3fc686498476685785118426cc9b5c.tar.gz
New hooks for reading/writing archives to/from a FILE * or
an in-memory buffer. PR: bin/86742
Diffstat (limited to 'lib/libarchive/archive_read_open_file.c')
-rw-r--r--lib/libarchive/archive_read_open_file.c177
1 files changed, 47 insertions, 130 deletions
diff --git a/lib/libarchive/archive_read_open_file.c b/lib/libarchive/archive_read_open_file.c
index cefc286..cb18fc3 100644
--- a/lib/libarchive/archive_read_open_file.c
+++ b/lib/libarchive/archive_read_open_file.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2003-2004 Tim Kientzle
+ * Copyright (c) 2003-2006 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -48,12 +48,10 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
-struct read_file_data {
- int fd;
+struct read_FILE_data {
+ FILE *f;
size_t block_size;
void *buffer;
- mode_t st_mode; /* Mode bits for opened file. */
- char filename[1]; /* Must be last! */
};
static int file_close(struct archive *, void *);
@@ -62,91 +60,54 @@ static ssize_t file_read(struct archive *, void *, const void **buff);
static ssize_t file_skip(struct archive *, void *, size_t request);
int
-archive_read_open_file(struct archive *a, const char *filename,
- size_t block_size)
+archive_read_open_FILE(struct archive *a, FILE *f)
{
- return (archive_read_open_filename(a, filename, block_size));
-}
+ struct read_FILE_data *mine;
-int
-archive_read_open_filename(struct archive *a, const char *filename,
- size_t block_size)
-{
- struct read_file_data *mine;
-
- if (filename == NULL || filename[0] == '\0') {
- mine = (struct read_file_data *)malloc(sizeof(*mine));
- if (mine == NULL) {
- archive_set_error(a, ENOMEM, "No memory");
- return (ARCHIVE_FATAL);
- }
- mine->filename[0] = '\0';
- } else {
- mine = (struct read_file_data *)malloc(sizeof(*mine) + strlen(filename));
- if (mine == NULL) {
- archive_set_error(a, ENOMEM, "No memory");
- return (ARCHIVE_FATAL);
- }
- strcpy(mine->filename, filename);
+ mine = (struct read_FILE_data *)malloc(sizeof(*mine));
+ if (mine == NULL) {
+ archive_set_error(a, ENOMEM, "No memory");
+ return (ARCHIVE_FATAL);
}
- mine->block_size = block_size;
- mine->buffer = NULL;
- mine->fd = -1;
- return (archive_read_open2(a, mine, file_open, file_read, file_skip, file_close));
+ mine->block_size = 128 * 1024;
+ mine->buffer = malloc(mine->block_size);
+ if (mine->buffer == NULL) {
+ archive_set_error(a, ENOMEM, "No memory");
+ free(mine);
+ return (ARCHIVE_FATAL);
+ }
+ mine->f = f;
+ return (archive_read_open2(a, mine, file_open, file_read,
+ file_skip, file_close));
}
static int
file_open(struct archive *a, void *client_data)
{
- struct read_file_data *mine = (struct read_file_data *)client_data;
+ struct read_FILE_data *mine = (struct read_FILE_data *)client_data;
struct stat st;
- mine->buffer = malloc(mine->block_size);
- if (mine->buffer == NULL) {
- archive_set_error(a, ENOMEM, "No memory");
- return (ARCHIVE_FATAL);
- }
- if (mine->filename[0] != '\0')
- mine->fd = open(mine->filename, O_RDONLY);
- else
- mine->fd = 0; /* Fake "open" for stdin. */
- if (mine->fd < 0) {
- archive_set_error(a, errno, "Failed to open '%s'",
- mine->filename);
- return (ARCHIVE_FATAL);
- }
- if (fstat(mine->fd, &st) == 0) {
- /* If we're reading a file from disk, ensure that we don't
- overwrite it with an extracted file. */
- if (S_ISREG(st.st_mode))
- archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);
- /* Remember mode so close can decide whether to flush. */
- mine->st_mode = st.st_mode;
- } else {
- if (mine->filename[0] == '\0')
- archive_set_error(a, errno, "Can't stat stdin");
- else
- archive_set_error(a, errno, "Can't stat '%s'",
- mine->filename);
- return (ARCHIVE_FATAL);
- }
- return (0);
+ /*
+ * If we can't fstat() the file, it may just be that
+ * it's not a file. (FILE * objects can wrap many kinds
+ * of I/O streams.)
+ */
+ if (fstat(fileno(mine->f), &st) == 0 && S_ISREG(st.st_mode))
+ archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);
+
+ return (ARCHIVE_OK);
}
static ssize_t
file_read(struct archive *a, void *client_data, const void **buff)
{
- struct read_file_data *mine = (struct read_file_data *)client_data;
+ struct read_FILE_data *mine = (struct read_FILE_data *)client_data;
ssize_t bytes_read;
*buff = mine->buffer;
- bytes_read = read(mine->fd, mine->buffer, mine->block_size);
+ bytes_read = fread(mine->buffer, 1, mine->block_size, mine->f);
if (bytes_read < 0) {
- if (mine->filename[0] == '\0')
- archive_set_error(a, errno, "Error reading stdin");
- else
- archive_set_error(a, errno, "Error reading '%s'",
- mine->filename);
+ archive_set_error(a, errno, "Error reading file");
}
return (bytes_read);
}
@@ -154,77 +115,33 @@ file_read(struct archive *a, void *client_data, const void **buff)
static ssize_t
file_skip(struct archive *a, void *client_data, size_t request)
{
- struct read_file_data *mine = (struct read_file_data *)client_data;
- off_t old_offset, new_offset;
+ struct read_FILE_data *mine = (struct read_FILE_data *)client_data;
- /* Reduce request to the next smallest multiple of block_size */
- request = (request / mine->block_size) * mine->block_size;
/*
- * Hurray for lazy evaluation: if the first lseek fails, the second
- * one will not be executed.
+ * Note: the 'fd' and 'filename' versions round the request
+ * down to a multiple of the block size to ensure proper
+ * operation on block-oriented media such as tapes. But stdio
+ * doesn't work with such media (it doesn't ensure blocking),
+ * so we don't need to bother.
*/
- if (((old_offset = lseek(mine->fd, 0, SEEK_CUR)) < 0) ||
- ((new_offset = lseek(mine->fd, request, SEEK_CUR)) < 0))
+#if HAVE_FSEEKO
+ if (fseeko(mine->f, request, SEEK_CUR) != 0)
+#else
+ if (fseek(mine->f, request, SEEK_CUR) != 0)
+#endif
{
- if (errno == ESPIPE)
- {
- /*
- * Failure to lseek() can be caused by the file
- * descriptor pointing to a pipe, socket or FIFO.
- * Return 0 here, so the compression layer will use
- * read()s instead to advance the file descriptor.
- * It's slower of course, but works as well.
- */
- return (0);
- }
- /*
- * There's been an error other than ESPIPE. This is most
- * likely caused by a programmer error (too large request)
- * or a corrupted archive file.
- */
- if (mine->filename[0] == '\0')
- /*
- * Should never get here, since lseek() on stdin ought
- * to return an ESPIPE error.
- */
- archive_set_error(a, errno, "Error seeking in stdin");
- else
- archive_set_error(a, errno, "Error seeking in '%s'",
- mine->filename);
- return (-1);
+ archive_set_error(a, errno, "Error skipping forward");
+ return (ARCHIVE_FATAL);
}
- return (new_offset - old_offset);
+ return (request);
}
static int
file_close(struct archive *a, void *client_data)
{
- struct read_file_data *mine = (struct read_file_data *)client_data;
+ struct read_FILE_data *mine = (struct read_FILE_data *)client_data;
(void)a; /* UNUSED */
-
- /*
- * Sometimes, we should flush the input before closing.
- * Regular files: faster to just close without flush.
- * Devices: must not flush (user might need to
- * read the "next" item on a non-rewind device).
- * Pipes and sockets: must flush (otherwise, the
- * program feeding the pipe or socket may complain).
- * Here, I flush everything except for regular files and
- * device nodes.
- */
- if (!S_ISREG(mine->st_mode)
- && !S_ISCHR(mine->st_mode)
- && !S_ISBLK(mine->st_mode)) {
- ssize_t bytesRead;
- do {
- bytesRead = read(mine->fd, mine->buffer,
- mine->block_size);
- } while (bytesRead > 0);
- }
- /* If a named file was opened, then it needs to be closed. */
- if (mine->filename[0] != '\0')
- close(mine->fd);
if (mine->buffer != NULL)
free(mine->buffer);
free(mine);
OpenPOWER on IntegriCloud