1 /* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
2
3 /*
4 * Copyright © 2014 Rob Clark <[email protected]>
5 * SPDX-License-Identifier: MIT
6 *
7 * Authors:
8 * Rob Clark <[email protected]>
9 */
10
11 #include <archive.h>
12 #include <fcntl.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
17 #include <archive_entry.h>
18
19 #include "io.h"
20
21 struct io {
22 struct archive *a;
23 struct archive_entry *entry;
24 unsigned offset;
25 };
26
27 static void
io_error(struct io * io)28 io_error(struct io *io)
29 {
30 fprintf(stderr, "%s\n", archive_error_string(io->a));
31 io_close(io);
32 }
33
34 static struct io *
io_new(void)35 io_new(void)
36 {
37 struct io *io = calloc(1, sizeof(*io));
38 int ret;
39
40 if (!io)
41 return NULL;
42
43 io->a = archive_read_new();
44 ret = archive_read_support_filter_gzip(io->a);
45 if (ret != ARCHIVE_OK) {
46 io_error(io);
47 return NULL;
48 }
49
50 ret = archive_read_support_filter_none(io->a);
51 if (ret != ARCHIVE_OK) {
52 io_error(io);
53 return NULL;
54 }
55
56 ret = archive_read_support_format_all(io->a);
57 if (ret != ARCHIVE_OK) {
58 io_error(io);
59 return NULL;
60 }
61
62 ret = archive_read_support_format_raw(io->a);
63 if (ret != ARCHIVE_OK) {
64 io_error(io);
65 return NULL;
66 }
67
68 return io;
69 }
70
71 struct io *
io_open(const char * filename)72 io_open(const char *filename)
73 {
74 struct io *io = io_new();
75 int ret;
76
77 if (!io)
78 return NULL;
79
80 ret = archive_read_open_filename(io->a, filename, 10240);
81 if (ret != ARCHIVE_OK) {
82 io_error(io);
83 return NULL;
84 }
85
86 ret = archive_read_next_header(io->a, &io->entry);
87 if (ret != ARCHIVE_OK) {
88 io_error(io);
89 return NULL;
90 }
91
92 return io;
93 }
94
95 struct io *
io_openfd(int fd)96 io_openfd(int fd)
97 {
98 struct io *io = io_new();
99 int ret;
100
101 if (!io)
102 return NULL;
103
104 ret = archive_read_open_fd(io->a, fd, 10240);
105 if (ret != ARCHIVE_OK) {
106 io_error(io);
107 return NULL;
108 }
109
110 ret = archive_read_next_header(io->a, &io->entry);
111 if (ret != ARCHIVE_OK) {
112 io_error(io);
113 return NULL;
114 }
115
116 return io;
117 }
118
119 void
io_close(struct io * io)120 io_close(struct io *io)
121 {
122 archive_read_free(io->a);
123 free(io);
124 }
125
126 unsigned
io_offset(struct io * io)127 io_offset(struct io *io)
128 {
129 return io->offset;
130 }
131
132 #include <assert.h>
133 int
io_readn(struct io * io,void * buf,int nbytes)134 io_readn(struct io *io, void *buf, int nbytes)
135 {
136 char *ptr = buf;
137 int ret = 0;
138 while (nbytes > 0) {
139 int n = archive_read_data(io->a, ptr, nbytes);
140 if (n < 0) {
141 fprintf(stderr, "%s\n", archive_error_string(io->a));
142 return n;
143 }
144 if (n == 0)
145 break;
146 ptr += n;
147 nbytes -= n;
148 ret += n;
149 io->offset += n;
150 }
151 return ret;
152 }
153