char can_skip;
};
-static int file_close(struct archive *, void *);
-static ssize_t file_read(struct archive *, void *, const void **buff);
-static int64_t file_skip(struct archive *, void *, int64_t request);
+static int FILE_close(struct archive *, void *);
+static ssize_t FILE_read(struct archive *, void *, const void **buff);
+static int64_t FILE_seek(struct archive *, void *, int64_t, int);
+static int64_t FILE_skip(struct archive *, void *, int64_t);
int
archive_read_open_FILE(struct archive *a, FILE *f)
void *b;
archive_clear_error(a);
- mine = malloc(sizeof(*mine));
+ mine = calloc(1, sizeof(*mine));
b = malloc(block_size);
if (mine == NULL || b == NULL) {
archive_set_error(a, ENOMEM, "No memory");
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;
- } else
- mine->can_skip = 0;
+ }
#if defined(__CYGWIN__) || defined(_WIN32)
setmode(fileno(mine->f), O_BINARY);
#endif
- archive_read_set_read_callback(a, file_read);
- archive_read_set_skip_callback(a, file_skip);
- archive_read_set_close_callback(a, file_close);
+ archive_read_set_read_callback(a, FILE_read);
+ archive_read_set_skip_callback(a, FILE_skip);
+ archive_read_set_seek_callback(a, FILE_seek);
+ archive_read_set_close_callback(a, FILE_close);
archive_read_set_callback_data(a, mine);
return (archive_read_open1(a));
}
static ssize_t
-file_read(struct archive *a, void *client_data, const void **buff)
+FILE_read(struct archive *a, void *client_data, const void **buff)
{
struct read_FILE_data *mine = (struct read_FILE_data *)client_data;
size_t bytes_read;
}
static int64_t
-file_skip(struct archive *a, void *client_data, int64_t request)
+FILE_skip(struct archive *a, void *client_data, int64_t request)
{
struct read_FILE_data *mine = (struct read_FILE_data *)client_data;
-#if HAVE_FSEEKO
- off_t skip = (off_t)request;
-#elif HAVE__FSEEKI64
+#if HAVE__FSEEKI64
int64_t skip = request;
+#elif HAVE_FSEEKO
+ off_t skip = (off_t)request;
#else
long skip = (long)request;
#endif
return (request);
}
+/*
+ * TODO: Store the offset and use it in the read callback.
+ */
+static int64_t
+FILE_seek(struct archive *a, void *client_data, int64_t request, int whence)
+{
+ struct read_FILE_data *mine = (struct read_FILE_data *)client_data;
+#if HAVE__FSEEKI64
+ int64_t skip = request;
+#elif HAVE_FSEEKO
+ off_t skip = (off_t)request;
+#else
+ long skip = (long)request;
+#endif
+ int skip_bits = sizeof(skip) * 8 - 1;
+ (void)a; /* UNUSED */
+
+ /* If request is too big for a long or an off_t, reduce it. */
+ if (sizeof(request) > sizeof(skip)) {
+ int64_t max_skip =
+ (((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1;
+ if (request > max_skip)
+ skip = max_skip;
+ }
+
+#ifdef __ANDROID__
+ /* Newer Android versions have fseeko...to meditate. */
+ int64_t ret = lseek(fileno(mine->f), skip, whence);
+ if (ret >= 0) {
+ return ret;
+ }
+#elif HAVE__FSEEKI64
+ if (_fseeki64(mine->f, skip, whence) == 0) {
+ return _ftelli64(mine->f);
+ }
+#elif HAVE_FSEEKO
+ if (fseeko(mine->f, skip, whence) == 0) {
+ return ftello(mine->f);
+ }
+#else
+ if (fseek(mine->f, skip, whence) == 0) {
+ return ftell(mine->f);
+ }
+#endif
+ /* If we arrive here, the input is corrupted or truncated so fail. */
+ archive_set_error(a, errno, "Error seeking in FILE* pointer");
+ return (ARCHIVE_FATAL);
+}
+
static int
-file_close(struct archive *a, void *client_data)
+FILE_close(struct archive *a, void *client_data)
{
struct read_FILE_data *mine = (struct read_FILE_data *)client_data;
free(mine->buffer);
free(mine);
return (ARCHIVE_OK);
-}
+}
\ No newline at end of file
struct archive *a;
FILE *f;
- f = fopen("test.tar", "wb");
+ f = fopen("test.7z", "wb");
assert(f != NULL);
if (f == NULL)
return;
/* Write an archive through this FILE *. */
assert((a = archive_write_new()) != NULL);
- assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_7zip(a));
assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_none(a));
assertEqualIntA(a, ARCHIVE_OK, archive_write_open_FILE(a, f));
fclose(f);
/*
- * Now, read the data back.
+ * Now, read the data back. 7z requiring seeking, that also
+ * tests that the seeking support works.
*/
- f = fopen("test.tar", "rb");
+ f = fopen("test.7z", "rb");
assert(f != NULL);
if (f == NULL)
return;