]>
git.ipfire.org Git - thirdparty/kmod.git/blob - libkmod/libkmod-file.c
2 * libkmod - interface to kernel module operations
4 * Copyright (C) 2011-2012 ProFUSION embedded systems
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 #include <sys/types.h>
32 #include "libkmod-private.h"
43 int (*load
)(struct kmod_file
*file
);
44 void (*unload
)(struct kmod_file
*file
);
57 const struct file_ops
*ops
;
58 const struct kmod_ctx
*ctx
;
63 static void xz_uncompress_belch(struct kmod_file
*file
, lzma_ret ret
)
67 ERR(file
->ctx
, "xz: %s\n", strerror(ENOMEM
));
69 case LZMA_FORMAT_ERROR
:
70 ERR(file
->ctx
, "xz: File format not recognized\n");
72 case LZMA_OPTIONS_ERROR
:
73 ERR(file
->ctx
, "xz: Unsupported compression options\n");
76 ERR(file
->ctx
, "xz: File is corrupt\n");
79 ERR(file
->ctx
, "xz: Unexpected end of input\n");
82 ERR(file
->ctx
, "xz: Internal error (bug)\n");
87 static int xz_uncompress(lzma_stream
*strm
, struct kmod_file
*file
)
89 uint8_t in_buf
[BUFSIZ
], out_buf
[BUFSIZ
];
90 lzma_action action
= LZMA_RUN
;
96 strm
->next_out
= out_buf
;
97 strm
->avail_out
= sizeof(out_buf
);
100 if (strm
->avail_in
== 0) {
101 ssize_t rdret
= read(file
->fd
, in_buf
, sizeof(in_buf
));
106 strm
->next_in
= in_buf
;
107 strm
->avail_in
= rdret
;
109 action
= LZMA_FINISH
;
111 ret
= lzma_code(strm
, action
);
112 if (strm
->avail_out
== 0 || ret
!= LZMA_OK
) {
113 size_t write_size
= BUFSIZ
- strm
->avail_out
;
114 char *tmp
= realloc(p
, total
+ write_size
);
119 memcpy(tmp
+ total
, out_buf
, write_size
);
122 strm
->next_out
= out_buf
;
123 strm
->avail_out
= BUFSIZ
;
125 if (ret
== LZMA_STREAM_END
)
127 if (ret
!= LZMA_OK
) {
128 xz_uncompress_belch(file
, ret
);
133 file
->xz_used
= true;
142 static int load_xz(struct kmod_file
*file
)
144 lzma_stream strm
= LZMA_STREAM_INIT
;
148 lzret
= lzma_stream_decoder(&strm
, UINT64_MAX
, LZMA_CONCATENATED
);
149 if (lzret
== LZMA_MEM_ERROR
) {
150 ERR(file
->ctx
, "xz: %s\n", strerror(ENOMEM
));
152 } else if (lzret
!= LZMA_OK
) {
153 ERR(file
->ctx
, "xz: Internal error (bug)\n");
156 ret
= xz_uncompress(&strm
, file
);
161 static void unload_xz(struct kmod_file
*file
)
168 static const char magic_xz
[] = {0xfd, '7', 'z', 'X', 'Z', 0};
172 #define READ_STEP (4 * 1024 * 1024)
173 static int load_zlib(struct kmod_file
*file
)
176 off_t did
= 0, total
= 0;
177 unsigned char *p
= NULL
;
180 file
->gzf
= gzdopen(file
->fd
, "rb");
181 if (file
->gzf
== NULL
) {
184 file
->fd
= -1; /* now owned by gzf due gzdopen() */
190 void *tmp
= realloc(p
, total
+ READ_STEP
);
199 r
= gzread(file
->gzf
, p
+ did
, total
- did
);
204 const char *gz_errmsg
= gzerror(file
->gzf
, &gzerr
);
206 ERR(file
->ctx
, "gzip: %s\n", gz_errmsg
);
208 /* gzip might not set errno here */
209 err
= gzerr
== Z_ERRNO
? -errno
: -EINVAL
;
224 static void unload_zlib(struct kmod_file
*file
)
226 if (file
->gzf
== NULL
)
229 gzclose(file
->gzf
); /* closes file->fd */
232 static const char magic_zlib
[] = {0x1f, 0x8b};
235 static const struct comp_type
{
237 const char *magic_bytes
;
238 const struct file_ops ops
;
241 {sizeof(magic_xz
), magic_xz
, {load_xz
, unload_xz
}},
244 {sizeof(magic_zlib
), magic_zlib
, {load_zlib
, unload_zlib
}},
246 {0, NULL
, {NULL
, NULL
}}
249 static int load_reg(struct kmod_file
*file
)
253 if (fstat(file
->fd
, &st
) < 0)
256 file
->size
= st
.st_size
;
257 file
->memory
= mmap(0, file
->size
, PROT_READ
, MAP_PRIVATE
, file
->fd
, 0);
258 if (file
->memory
== MAP_FAILED
)
263 static void unload_reg(struct kmod_file
*file
)
265 munmap(file
->memory
, file
->size
);
268 static const struct file_ops reg_ops
= {
272 struct kmod_elf
*kmod_file_get_elf(struct kmod_file
*file
)
277 file
->elf
= kmod_elf_new(file
->memory
, file
->size
);
281 struct kmod_file
*kmod_file_open(const struct kmod_ctx
*ctx
,
282 const char *filename
)
284 struct kmod_file
*file
= calloc(1, sizeof(struct kmod_file
));
285 const struct comp_type
*itr
;
286 size_t magic_size_max
= 0;
292 file
->fd
= open(filename
, O_RDONLY
|O_CLOEXEC
);
298 for (itr
= comp_types
; itr
->ops
.load
!= NULL
; itr
++) {
299 if (magic_size_max
< itr
->magic_size
)
300 magic_size_max
= itr
->magic_size
;
303 if (magic_size_max
> 0) {
304 char *buf
= alloca(magic_size_max
+ 1);
311 sz
= read_str_safe(file
->fd
, buf
, magic_size_max
+ 1);
312 lseek(file
->fd
, 0, SEEK_SET
);
313 if (sz
!= (ssize_t
)magic_size_max
) {
321 for (itr
= comp_types
; itr
->ops
.load
!= NULL
; itr
++) {
322 if (memcmp(buf
, itr
->magic_bytes
, itr
->magic_size
) == 0)
325 if (itr
->ops
.load
!= NULL
)
326 file
->ops
= &itr
->ops
;
329 if (file
->ops
== NULL
)
330 file
->ops
= ®_ops
;
332 err
= file
->ops
->load(file
);
346 void *kmod_file_get_contents(const struct kmod_file
*file
)
351 off_t
kmod_file_get_size(const struct kmod_file
*file
)
356 void kmod_file_unref(struct kmod_file
*file
)
359 kmod_elf_unref(file
->elf
);
361 file
->ops
->unload(file
);