1 /* 2 * Copyright (C) 2016 Jo-Philipp Wich <jo@mein.io> 3 * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> 4 * 5 * Zlib decrompression utility routines. 6 * 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. 11 * 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. 16 * 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. 20 */ 21 22 #include <string.h> 23 #include <errno.h> 24 #include <fcntl.h> 25 #include <unistd.h> 26 #include <poll.h> 27 #include <stdlib.h> 28 #include <sys/stat.h> 29 #include <sys/wait.h> 30 31 #include "gzip.h" 32 33 static void to_devnull(int fd) 34 { 35 int devnull = open("/dev/null", fd ? O_WRONLY : O_RDONLY); 36 37 if (devnull >= 0) 38 dup2(devnull, fd); 39 40 if (devnull > STDERR_FILENO) 41 close(devnull); 42 } 43 44 static void *gzip_thread(void *ptr) 45 { 46 struct gzip_handle *zh = ptr; 47 char buf[4096]; 48 int len = 0, ret; 49 50 while (1) { 51 if (zh->file) 52 len = fread(buf, 1, sizeof(buf), zh->file); 53 else if (zh->gzip) 54 len = gzip_read(zh->gzip, buf, sizeof(buf)); 55 56 if (len <= 0) 57 break; 58 59 do { 60 ret = write(zh->wfd, buf, len); 61 } while (ret == -1 && errno == EINTR); 62 } 63 64 close(zh->wfd); 65 zh->wfd = -1; 66 67 return NULL; 68 } 69 70 int gzip_exec(struct gzip_handle *zh, const char *filename) 71 { 72 int rpipe[2] = { -1, -1 }, wpipe[2] = { 73 -1, -1}; 74 struct sigaction pipe_sa = {.sa_handler = SIG_IGN }; 75 76 zh->rfd = -1; 77 zh->wfd = -1; 78 79 if (sigaction(SIGPIPE, &pipe_sa, &zh->pipe_sa) < 0) 80 return -1; 81 82 if (pipe(rpipe) < 0) 83 return -1; 84 85 if (!filename && pipe(wpipe) < 0) { 86 close(rpipe[0]); 87 close(rpipe[1]); 88 return -1; 89 } 90 91 zh->pid = vfork(); 92 93 switch (zh->pid) { 94 case -1: 95 return -1; 96 97 case 0: 98 to_devnull(STDERR_FILENO); 99 100 if (filename) { 101 to_devnull(STDIN_FILENO); 102 } else { 103 dup2(wpipe[0], STDIN_FILENO); 104 close(wpipe[0]); 105 close(wpipe[1]); 106 } 107 108 dup2(rpipe[1], STDOUT_FILENO); 109 close(rpipe[0]); 110 close(rpipe[1]); 111 112 execlp("gzip", "gzip", "-d", "-c", filename, NULL); 113 exit(-1); 114 115 default: 116 zh->rfd = rpipe[0]; 117 zh->wfd = wpipe[1]; 118 119 fcntl(zh->rfd, F_SETFD, fcntl(zh->rfd, F_GETFD) | FD_CLOEXEC); 120 close(rpipe[1]); 121 122 if (zh->wfd >= 0) { 123 fcntl(zh->wfd, F_SETFD, 124 fcntl(zh->wfd, F_GETFD) | FD_CLOEXEC); 125 close(wpipe[0]); 126 pthread_create(&zh->thread, NULL, gzip_thread, zh); 127 } 128 } 129 130 return 0; 131 } 132 133 ssize_t gzip_read(struct gzip_handle * zh, void *buf, ssize_t len) 134 { 135 ssize_t ret; 136 137 do { 138 ret = read(zh->rfd, buf, len); 139 } while (ret == -1 && errno != EINTR); 140 141 return ret; 142 } 143 144 ssize_t gzip_copy(struct gzip_handle * zh, FILE * out, ssize_t len) 145 { 146 char buf[4096]; 147 ssize_t rlen, total = 0; 148 149 while (len > 0) { 150 rlen = gzip_read(zh, buf, 151 (len > sizeof(buf)) ? sizeof(buf) : len); 152 153 if (rlen <= 0) 154 break; 155 156 if (out != NULL) { 157 if (fwrite(buf, 1, rlen, out) != rlen) 158 break; 159 } 160 161 len -= rlen; 162 total += rlen; 163 } 164 165 return total; 166 } 167 168 FILE *gzip_fdopen(struct gzip_handle * zh, const char *filename) 169 { 170 memset(zh, 0, sizeof(*zh)); 171 172 if (!filename || gzip_exec(zh, filename) < 0) 173 return NULL; 174 175 fcntl(zh->rfd, F_SETFL, fcntl(zh->rfd, F_GETFL) & ~O_NONBLOCK); 176 177 return fdopen(zh->rfd, "r"); 178 } 179 180 int gzip_close(struct gzip_handle *zh) 181 { 182 int code = -1; 183 184 if (zh->rfd >= 0) 185 close(zh->rfd); 186 187 if (zh->wfd >= 0) 188 close(zh->wfd); 189 190 if (zh->pid > 0) { 191 kill(zh->pid, SIGKILL); 192 waitpid(zh->pid, &code, 0); 193 } 194 195 if (zh->file) 196 fclose(zh->file); 197 198 if (zh->thread) 199 pthread_join(zh->thread, NULL); 200 201 sigaction(SIGPIPE, &zh->pipe_sa, NULL); 202 203 return WIFEXITED(code) ? WEXITSTATUS(code) : -1; 204 } 205
This page was automatically generated by LXR 0.3.1. • OpenWrt