2 * Copyright (C) 2016 Jo-Philipp Wich <jo@mein.io>
3 * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
5 * Zlib decrompression utility routines.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Library General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
33 static void to_devnull(int fd
)
35 int devnull
= open("/dev/null", fd
? O_WRONLY
: O_RDONLY
);
40 if (devnull
> STDERR_FILENO
)
44 static void *gzip_thread(void *ptr
)
46 struct gzip_handle
*zh
= ptr
;
52 len
= fread(buf
, 1, sizeof(buf
), zh
->file
);
54 len
= gzip_read(zh
->gzip
, buf
, sizeof(buf
));
60 ret
= write(zh
->wfd
, buf
, len
);
61 } while (ret
== -1 && errno
== EINTR
);
70 int gzip_exec(struct gzip_handle
*zh
, const char *filename
)
72 int rpipe
[2] = { -1, -1 }, wpipe
[2] = {
74 struct sigaction pipe_sa
= {.sa_handler
= SIG_IGN
};
79 if (sigaction(SIGPIPE
, &pipe_sa
, &zh
->pipe_sa
) < 0)
85 if (!filename
&& pipe(wpipe
) < 0) {
98 to_devnull(STDERR_FILENO
);
101 to_devnull(STDIN_FILENO
);
103 dup2(wpipe
[0], STDIN_FILENO
);
108 dup2(rpipe
[1], STDOUT_FILENO
);
112 execlp("gzip", "gzip", "-d", "-c", filename
, NULL
);
119 fcntl(zh
->rfd
, F_SETFD
, fcntl(zh
->rfd
, F_GETFD
) | FD_CLOEXEC
);
123 fcntl(zh
->wfd
, F_SETFD
,
124 fcntl(zh
->wfd
, F_GETFD
) | FD_CLOEXEC
);
126 pthread_create(&zh
->thread
, NULL
, gzip_thread
, zh
);
133 ssize_t
gzip_read(struct gzip_handle
* zh
, void *buf
, ssize_t len
)
138 ret
= read(zh
->rfd
, buf
, len
);
139 } while (ret
== -1 && errno
!= EINTR
);
144 ssize_t
gzip_copy(struct gzip_handle
* zh
, FILE * out
, ssize_t len
)
147 ssize_t rlen
, total
= 0;
150 rlen
= gzip_read(zh
, buf
,
151 (len
> sizeof(buf
)) ? sizeof(buf
) : len
);
157 if (fwrite(buf
, 1, rlen
, out
) != rlen
)
168 FILE *gzip_fdopen(struct gzip_handle
* zh
, const char *filename
)
170 memset(zh
, 0, sizeof(*zh
));
172 if (!filename
|| gzip_exec(zh
, filename
) < 0)
175 fcntl(zh
->rfd
, F_SETFL
, fcntl(zh
->rfd
, F_GETFL
) & ~O_NONBLOCK
);
177 return fdopen(zh
->rfd
, "r");
180 int gzip_close(struct gzip_handle
*zh
)
191 kill(zh
->pid
, SIGKILL
);
192 waitpid(zh
->pid
, &code
, 0);
199 pthread_join(zh
->thread
, NULL
);
201 sigaction(SIGPIPE
, &zh
->pipe_sa
, NULL
);
203 return WIFEXITED(code
) ? WEXITSTATUS(code
) : -1;