• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Author: Jason Tang	  <jtang@tresys.com>
2  *         Christopher Ashworth <cashworth@tresys.com>
3  *         Ondrej Mosnacek <omosnacek@gmail.com>
4  *
5  * Copyright (C) 2004-2006 Tresys Technology, LLC
6  * Copyright (C) 2005-2021 Red Hat, Inc.
7  *
8  *  This library is free software; you can redistribute it and/or
9  *  modify it under the terms of the GNU Lesser General Public
10  *  License as published by the Free Software Foundation; either
11  *  version 2.1 of the License, or (at your option) any later version.
12  *
13  *  This library is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  *  Lesser General Public License for more details.
17  *
18  *  You should have received a copy of the GNU Lesser General Public
19  *  License along with this library; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22 
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdint.h>
26 
27 #include <unistd.h>
28 #include <fcntl.h>
29 
30 #include <bzlib.h>
31 
32 #include "compressed_file.h"
33 
34 #include "debug.h"
35 
36 #define BZ2_MAGICSTR "BZh"
37 #define BZ2_MAGICLEN (sizeof(BZ2_MAGICSTR)-1)
38 
39 /* bzip() a data to a file, returning the total number of compressed bytes
40  * in the file.  Returns -1 if file could not be compressed. */
bzip(semanage_handle_t * sh,const char * filename,void * data,size_t num_bytes)41 static int bzip(semanage_handle_t *sh, const char *filename, void *data,
42 		size_t num_bytes)
43 {
44 	BZFILE* b;
45 	size_t  size = 1<<16;
46 	int     bzerror;
47 	size_t  total = 0;
48 	size_t len = 0;
49 	FILE *f;
50 
51 	if ((f = fopen(filename, "wb")) == NULL) {
52 		return -1;
53 	}
54 
55 	if (!sh->conf->bzip_blocksize) {
56 		if (fwrite(data, 1, num_bytes, f) < num_bytes) {
57 			fclose(f);
58 			return -1;
59 		}
60 		fclose(f);
61 		return 0;
62 	}
63 
64 	b = BZ2_bzWriteOpen( &bzerror, f, sh->conf->bzip_blocksize, 0, 0);
65 	if (bzerror != BZ_OK) {
66 		BZ2_bzWriteClose ( &bzerror, b, 1, 0, 0 );
67 		fclose(f);
68 		return -1;
69 	}
70 
71 	while ( num_bytes > total ) {
72 		if (num_bytes - total > size) {
73 			len = size;
74 		} else {
75 			len = num_bytes - total;
76 		}
77 		BZ2_bzWrite ( &bzerror, b, (uint8_t *)data + total, len );
78 		if (bzerror == BZ_IO_ERROR) {
79 			BZ2_bzWriteClose ( &bzerror, b, 1, 0, 0 );
80 			fclose(f);
81 			return -1;
82 		}
83 		total += len;
84 	}
85 
86 	BZ2_bzWriteClose ( &bzerror, b, 0, 0, 0 );
87 	fclose(f);
88 	if (bzerror == BZ_IO_ERROR) {
89 		return -1;
90 	}
91 	return 0;
92 }
93 
94 /* bunzip() a file to '*data', returning the total number of uncompressed bytes
95  * in the file.  Returns -1 if file could not be decompressed. */
bunzip(semanage_handle_t * sh,FILE * f,void ** data)96 static ssize_t bunzip(semanage_handle_t *sh, FILE *f, void **data)
97 {
98 	BZFILE*  b = NULL;
99 	size_t   nBuf;
100 	uint8_t* buf = NULL;
101 	size_t   size = 1<<18;
102 	size_t   bufsize = size;
103 	int      bzerror;
104 	size_t   total = 0;
105 	uint8_t* uncompress = NULL;
106 	uint8_t* tmpalloc = NULL;
107 	int      ret = -1;
108 
109 	buf = malloc(bufsize);
110 	if (buf == NULL) {
111 		ERR(sh, "Failure allocating memory.");
112 		goto exit;
113 	}
114 
115 	/* Check if the file is bzipped */
116 	bzerror = fread(buf, 1, BZ2_MAGICLEN, f);
117 	rewind(f);
118 	if ((bzerror != BZ2_MAGICLEN) || memcmp(buf, BZ2_MAGICSTR, BZ2_MAGICLEN)) {
119 		goto exit;
120 	}
121 
122 	b = BZ2_bzReadOpen ( &bzerror, f, 0, sh->conf->bzip_small, NULL, 0 );
123 	if ( bzerror != BZ_OK ) {
124 		ERR(sh, "Failure opening bz2 archive.");
125 		goto exit;
126 	}
127 
128 	uncompress = malloc(size);
129 	if (uncompress == NULL) {
130 		ERR(sh, "Failure allocating memory.");
131 		goto exit;
132 	}
133 
134 	while ( bzerror == BZ_OK) {
135 		nBuf = BZ2_bzRead ( &bzerror, b, buf, bufsize);
136 		if (( bzerror == BZ_OK ) || ( bzerror == BZ_STREAM_END )) {
137 			if (total + nBuf > size) {
138 				size *= 2;
139 				tmpalloc = realloc(uncompress, size);
140 				if (tmpalloc == NULL) {
141 					ERR(sh, "Failure allocating memory.");
142 					goto exit;
143 				}
144 				uncompress = tmpalloc;
145 			}
146 			memcpy(&uncompress[total], buf, nBuf);
147 			total += nBuf;
148 		}
149 	}
150 	if ( bzerror != BZ_STREAM_END ) {
151 		ERR(sh, "Failure reading bz2 archive.");
152 		goto exit;
153 	}
154 
155 	ret = total;
156 	*data = uncompress;
157 
158 exit:
159 	BZ2_bzReadClose ( &bzerror, b );
160 	free(buf);
161 	if ( ret < 0 ) {
162 		free(uncompress);
163 	}
164 	return ret;
165 }
166 
map_compressed_file(semanage_handle_t * sh,const char * path,struct file_contents * contents)167 int map_compressed_file(semanage_handle_t *sh, const char *path,
168 			struct file_contents *contents)
169 {
170 	ssize_t size = -1;
171 	void *uncompress;
172 	int ret = 0, fd = -1;
173 	FILE *file = NULL;
174 
175 	fd = open(path, O_RDONLY);
176 	if (fd == -1) {
177 		ERR(sh, "Unable to open %s\n", path);
178 		return -1;
179 	}
180 
181 	file = fdopen(fd, "r");
182 	if (file == NULL) {
183 		ERR(sh, "Unable to open %s\n", path);
184 		close(fd);
185 		return -1;
186 	}
187 
188 	if ((size = bunzip(sh, file, &uncompress)) >= 0) {
189 		contents->data = uncompress;
190 		contents->len = size;
191 		contents->compressed = 1;
192 	} else {
193 		struct stat sb;
194 		if (fstat(fd, &sb) == -1 ||
195 		    (uncompress = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) ==
196 		    MAP_FAILED) {
197 			ret = -1;
198 		} else {
199 			contents->data = uncompress;
200 			contents->len = sb.st_size;
201 			contents->compressed = 0;
202 		}
203 	}
204 	fclose(file);
205 	return ret;
206 }
207 
unmap_compressed_file(struct file_contents * contents)208 void unmap_compressed_file(struct file_contents *contents)
209 {
210 	if (!contents->data)
211 		return;
212 
213 	if (contents->compressed) {
214 		free(contents->data);
215 	} else {
216 		munmap(contents->data, contents->len);
217 	}
218 }
219 
write_compressed_file(semanage_handle_t * sh,const char * path,void * data,size_t len)220 int write_compressed_file(semanage_handle_t *sh, const char *path,
221 			  void *data, size_t len)
222 {
223 	return bzip(sh, path, data, len);
224 }
225