]>
git.ipfire.org Git - thirdparty/kmod.git/blob - libkmod/libkmod-file.c
2 * libkmod - interface to kernel module operations
4 * Copyright (C) 2011-2013 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
);
58 const struct file_ops
*ops
;
59 const struct kmod_ctx
*ctx
;
64 static void xz_uncompress_belch(struct kmod_file
*file
, lzma_ret ret
)
68 ERR(file
->ctx
, "xz: %s\n", strerror(ENOMEM
));
70 case LZMA_FORMAT_ERROR
:
71 ERR(file
->ctx
, "xz: File format not recognized\n");
73 case LZMA_OPTIONS_ERROR
:
74 ERR(file
->ctx
, "xz: Unsupported compression options\n");
77 ERR(file
->ctx
, "xz: File is corrupt\n");
80 ERR(file
->ctx
, "xz: Unexpected end of input\n");
83 ERR(file
->ctx
, "xz: Internal error (bug)\n");
88 static int xz_uncompress(lzma_stream
*strm
, struct kmod_file
*file
)
90 uint8_t in_buf
[BUFSIZ
], out_buf
[BUFSIZ
];
91 lzma_action action
= LZMA_RUN
;
97 strm
->next_out
= out_buf
;
98 strm
->avail_out
= sizeof(out_buf
);
101 if (strm
->avail_in
== 0) {
102 ssize_t rdret
= read(file
->fd
, in_buf
, sizeof(in_buf
));
107 strm
->next_in
= in_buf
;
108 strm
->avail_in
= rdret
;
110 action
= LZMA_FINISH
;
112 ret
= lzma_code(strm
, action
);
113 if (strm
->avail_out
== 0 || ret
!= LZMA_OK
) {
114 size_t write_size
= BUFSIZ
- strm
->avail_out
;
115 char *tmp
= realloc(p
, total
+ write_size
);
120 memcpy(tmp
+ total
, out_buf
, write_size
);
123 strm
->next_out
= out_buf
;
124 strm
->avail_out
= BUFSIZ
;
126 if (ret
== LZMA_STREAM_END
)
128 if (ret
!= LZMA_OK
) {
129 xz_uncompress_belch(file
, ret
);
134 file
->xz_used
= true;
143 static int load_xz(struct kmod_file
*file
)
145 lzma_stream strm
= LZMA_STREAM_INIT
;
149 lzret
= lzma_stream_decoder(&strm
, UINT64_MAX
, LZMA_CONCATENATED
);
150 if (lzret
== LZMA_MEM_ERROR
) {
151 ERR(file
->ctx
, "xz: %s\n", strerror(ENOMEM
));
153 } else if (lzret
!= LZMA_OK
) {
154 ERR(file
->ctx
, "xz: Internal error (bug)\n");
157 ret
= xz_uncompress(&strm
, file
);
162 static void unload_xz(struct kmod_file
*file
)
169 static const char magic_xz
[] = {0xfd, '7', 'z', 'X', 'Z', 0};
173 #define READ_STEP (4 * 1024 * 1024)
174 static int load_zlib(struct kmod_file
*file
)
177 off_t did
= 0, total
= 0;
178 unsigned char *p
= NULL
;
181 file
->gzf
= gzdopen(file
->fd
, "rb");
182 if (file
->gzf
== NULL
) {
185 file
->fd
= -1; /* now owned by gzf due gzdopen() */
191 void *tmp
= realloc(p
, total
+ READ_STEP
);
200 r
= gzread(file
->gzf
, p
+ did
, total
- did
);
205 const char *gz_errmsg
= gzerror(file
->gzf
, &gzerr
);
207 ERR(file
->ctx
, "gzip: %s\n", gz_errmsg
);
209 /* gzip might not set errno here */
210 err
= gzerr
== Z_ERRNO
? -errno
: -EINVAL
;
225 static void unload_zlib(struct kmod_file
*file
)
227 if (file
->gzf
== NULL
)
230 gzclose(file
->gzf
); /* closes file->fd */
233 static const char magic_zlib
[] = {0x1f, 0x8b};
236 static const struct comp_type
{
238 const char *magic_bytes
;
239 const struct file_ops ops
;
242 {sizeof(magic_xz
), magic_xz
, {load_xz
, unload_xz
}},
245 {sizeof(magic_zlib
), magic_zlib
, {load_zlib
, unload_zlib
}},
247 {0, NULL
, {NULL
, NULL
}}
250 static int load_reg(struct kmod_file
*file
)
254 if (fstat(file
->fd
, &st
) < 0)
257 file
->size
= st
.st_size
;
258 file
->memory
= mmap(0, file
->size
, PROT_READ
, MAP_PRIVATE
, file
->fd
, 0);
259 if (file
->memory
== MAP_FAILED
)
265 static void unload_reg(struct kmod_file
*file
)
267 munmap(file
->memory
, file
->size
);
270 static const struct file_ops reg_ops
= {
274 struct kmod_elf
*kmod_file_get_elf(struct kmod_file
*file
)
279 file
->elf
= kmod_elf_new(file
->memory
, file
->size
);
283 struct kmod_file
*kmod_file_open(const struct kmod_ctx
*ctx
,
284 const char *filename
)
286 struct kmod_file
*file
= calloc(1, sizeof(struct kmod_file
));
287 const struct comp_type
*itr
;
288 size_t magic_size_max
= 0;
294 file
->fd
= open(filename
, O_RDONLY
|O_CLOEXEC
);
300 for (itr
= comp_types
; itr
->ops
.load
!= NULL
; itr
++) {
301 if (magic_size_max
< itr
->magic_size
)
302 magic_size_max
= itr
->magic_size
;
305 file
->direct
= false;
306 if (magic_size_max
> 0) {
307 char *buf
= alloca(magic_size_max
+ 1);
314 sz
= read_str_safe(file
->fd
, buf
, magic_size_max
+ 1);
315 lseek(file
->fd
, 0, SEEK_SET
);
316 if (sz
!= (ssize_t
)magic_size_max
) {
324 for (itr
= comp_types
; itr
->ops
.load
!= NULL
; itr
++) {
325 if (memcmp(buf
, itr
->magic_bytes
, itr
->magic_size
) == 0)
328 if (itr
->ops
.load
!= NULL
)
329 file
->ops
= &itr
->ops
;
332 if (file
->ops
== NULL
)
333 file
->ops
= ®_ops
;
335 err
= file
->ops
->load(file
);
349 void *kmod_file_get_contents(const struct kmod_file
*file
)
354 off_t
kmod_file_get_size(const struct kmod_file
*file
)
359 bool kmod_file_get_direct(const struct kmod_file
*file
)
364 int kmod_file_get_fd(const struct kmod_file
*file
)
369 void kmod_file_unref(struct kmod_file
*file
)
372 kmod_elf_unref(file
->elf
);
374 file
->ops
->unload(file
);