17ec681f3Smrg/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
27ec681f3Smrg
37ec681f3Smrg/*
47ec681f3Smrg * Copyright (C) 2014 Rob Clark <robclark@freedesktop.org>
57ec681f3Smrg *
67ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
77ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
87ec681f3Smrg * to deal in the Software without restriction, including without limitation
97ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
107ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
117ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
127ec681f3Smrg *
137ec681f3Smrg * The above copyright notice and this permission notice (including the next
147ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
157ec681f3Smrg * Software.
167ec681f3Smrg *
177ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
187ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
197ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
207ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
217ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
227ec681f3Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
237ec681f3Smrg * SOFTWARE.
247ec681f3Smrg *
257ec681f3Smrg * Authors:
267ec681f3Smrg *    Rob Clark <robclark@freedesktop.org>
277ec681f3Smrg */
287ec681f3Smrg
297ec681f3Smrg#include <archive.h>
307ec681f3Smrg#include <fcntl.h>
317ec681f3Smrg#include <stdlib.h>
327ec681f3Smrg#include <string.h>
337ec681f3Smrg#include <sys/stat.h>
347ec681f3Smrg#include <sys/types.h>
357ec681f3Smrg#include <archive_entry.h>
367ec681f3Smrg
377ec681f3Smrg#include "io.h"
387ec681f3Smrg
397ec681f3Smrgstruct io {
407ec681f3Smrg   struct archive *a;
417ec681f3Smrg   struct archive_entry *entry;
427ec681f3Smrg   unsigned offset;
437ec681f3Smrg};
447ec681f3Smrg
457ec681f3Smrgstatic void
467ec681f3Smrgio_error(struct io *io)
477ec681f3Smrg{
487ec681f3Smrg   fprintf(stderr, "%s\n", archive_error_string(io->a));
497ec681f3Smrg   io_close(io);
507ec681f3Smrg}
517ec681f3Smrg
527ec681f3Smrgstatic struct io *
537ec681f3Smrgio_new(void)
547ec681f3Smrg{
557ec681f3Smrg   struct io *io = calloc(1, sizeof(*io));
567ec681f3Smrg   int ret;
577ec681f3Smrg
587ec681f3Smrg   if (!io)
597ec681f3Smrg      return NULL;
607ec681f3Smrg
617ec681f3Smrg   io->a = archive_read_new();
627ec681f3Smrg   ret = archive_read_support_filter_gzip(io->a);
637ec681f3Smrg   if (ret != ARCHIVE_OK) {
647ec681f3Smrg      io_error(io);
657ec681f3Smrg      return NULL;
667ec681f3Smrg   }
677ec681f3Smrg
687ec681f3Smrg   ret = archive_read_support_filter_none(io->a);
697ec681f3Smrg   if (ret != ARCHIVE_OK) {
707ec681f3Smrg      io_error(io);
717ec681f3Smrg      return NULL;
727ec681f3Smrg   }
737ec681f3Smrg
747ec681f3Smrg   ret = archive_read_support_format_all(io->a);
757ec681f3Smrg   if (ret != ARCHIVE_OK) {
767ec681f3Smrg      io_error(io);
777ec681f3Smrg      return NULL;
787ec681f3Smrg   }
797ec681f3Smrg
807ec681f3Smrg   ret = archive_read_support_format_raw(io->a);
817ec681f3Smrg   if (ret != ARCHIVE_OK) {
827ec681f3Smrg      io_error(io);
837ec681f3Smrg      return NULL;
847ec681f3Smrg   }
857ec681f3Smrg
867ec681f3Smrg   return io;
877ec681f3Smrg}
887ec681f3Smrg
897ec681f3Smrgstruct io *
907ec681f3Smrgio_open(const char *filename)
917ec681f3Smrg{
927ec681f3Smrg   struct io *io = io_new();
937ec681f3Smrg   int ret;
947ec681f3Smrg
957ec681f3Smrg   if (!io)
967ec681f3Smrg      return NULL;
977ec681f3Smrg
987ec681f3Smrg   ret = archive_read_open_filename(io->a, filename, 10240);
997ec681f3Smrg   if (ret != ARCHIVE_OK) {
1007ec681f3Smrg      io_error(io);
1017ec681f3Smrg      return NULL;
1027ec681f3Smrg   }
1037ec681f3Smrg
1047ec681f3Smrg   ret = archive_read_next_header(io->a, &io->entry);
1057ec681f3Smrg   if (ret != ARCHIVE_OK) {
1067ec681f3Smrg      io_error(io);
1077ec681f3Smrg      return NULL;
1087ec681f3Smrg   }
1097ec681f3Smrg
1107ec681f3Smrg   return io;
1117ec681f3Smrg}
1127ec681f3Smrg
1137ec681f3Smrgstruct io *
1147ec681f3Smrgio_openfd(int fd)
1157ec681f3Smrg{
1167ec681f3Smrg   struct io *io = io_new();
1177ec681f3Smrg   int ret;
1187ec681f3Smrg
1197ec681f3Smrg   if (!io)
1207ec681f3Smrg      return NULL;
1217ec681f3Smrg
1227ec681f3Smrg   ret = archive_read_open_fd(io->a, fd, 10240);
1237ec681f3Smrg   if (ret != ARCHIVE_OK) {
1247ec681f3Smrg      io_error(io);
1257ec681f3Smrg      return NULL;
1267ec681f3Smrg   }
1277ec681f3Smrg
1287ec681f3Smrg   ret = archive_read_next_header(io->a, &io->entry);
1297ec681f3Smrg   if (ret != ARCHIVE_OK) {
1307ec681f3Smrg      io_error(io);
1317ec681f3Smrg      return NULL;
1327ec681f3Smrg   }
1337ec681f3Smrg
1347ec681f3Smrg   return io;
1357ec681f3Smrg}
1367ec681f3Smrg
1377ec681f3Smrgvoid
1387ec681f3Smrgio_close(struct io *io)
1397ec681f3Smrg{
1407ec681f3Smrg   archive_read_free(io->a);
1417ec681f3Smrg   free(io);
1427ec681f3Smrg}
1437ec681f3Smrg
1447ec681f3Smrgunsigned
1457ec681f3Smrgio_offset(struct io *io)
1467ec681f3Smrg{
1477ec681f3Smrg   return io->offset;
1487ec681f3Smrg}
1497ec681f3Smrg
1507ec681f3Smrg#include <assert.h>
1517ec681f3Smrgint
1527ec681f3Smrgio_readn(struct io *io, void *buf, int nbytes)
1537ec681f3Smrg{
1547ec681f3Smrg   char *ptr = buf;
1557ec681f3Smrg   int ret = 0;
1567ec681f3Smrg   while (nbytes > 0) {
1577ec681f3Smrg      int n = archive_read_data(io->a, ptr, nbytes);
1587ec681f3Smrg      if (n < 0) {
1597ec681f3Smrg         fprintf(stderr, "%s\n", archive_error_string(io->a));
1607ec681f3Smrg         return n;
1617ec681f3Smrg      }
1627ec681f3Smrg      if (n == 0)
1637ec681f3Smrg         break;
1647ec681f3Smrg      ptr += n;
1657ec681f3Smrg      nbytes -= n;
1667ec681f3Smrg      ret += n;
1677ec681f3Smrg      io->offset += n;
1687ec681f3Smrg   }
1697ec681f3Smrg   return ret;
1707ec681f3Smrg}
171