• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/opkg-lede/libbb/gzip.c

  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