]>
git.ipfire.org Git - thirdparty/kmod.git/blob - libkmod/libkmod-file.c
45ae4a346bd00d7180a196f155187a0bb683b2e2
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
28 #include <sys/types.h>
37 #include <shared/util.h>
40 #include "libkmod-internal.h"
44 int (*load
)(struct kmod_file
*file
);
45 void (*unload
)(struct kmod_file
*file
);
59 const struct file_ops
*ops
;
60 const struct kmod_ctx
*ctx
;
65 static void xz_uncompress_belch(struct kmod_file
*file
, lzma_ret ret
)
69 ERR(file
->ctx
, "xz: %s\n", strerror(ENOMEM
));
71 case LZMA_FORMAT_ERROR
:
72 ERR(file
->ctx
, "xz: File format not recognized\n");
74 case LZMA_OPTIONS_ERROR
:
75 ERR(file
->ctx
, "xz: Unsupported compression options\n");
78 ERR(file
->ctx
, "xz: File is corrupt\n");
81 ERR(file
->ctx
, "xz: Unexpected end of input\n");
84 ERR(file
->ctx
, "xz: Internal error (bug)\n");
89 static int xz_uncompress(lzma_stream
*strm
, struct kmod_file
*file
)
91 uint8_t in_buf
[BUFSIZ
], out_buf
[BUFSIZ
];
92 lzma_action action
= LZMA_RUN
;
98 strm
->next_out
= out_buf
;
99 strm
->avail_out
= sizeof(out_buf
);
102 if (strm
->avail_in
== 0) {
103 ssize_t rdret
= read(file
->fd
, in_buf
, sizeof(in_buf
));
108 strm
->next_in
= in_buf
;
109 strm
->avail_in
= rdret
;
111 action
= LZMA_FINISH
;
113 ret
= lzma_code(strm
, action
);
114 if (strm
->avail_out
== 0 || ret
!= LZMA_OK
) {
115 size_t write_size
= BUFSIZ
- strm
->avail_out
;
116 char *tmp
= realloc(p
, total
+ write_size
);
121 memcpy(tmp
+ total
, out_buf
, write_size
);
124 strm
->next_out
= out_buf
;
125 strm
->avail_out
= BUFSIZ
;
127 if (ret
== LZMA_STREAM_END
)
129 if (ret
!= LZMA_OK
) {
130 xz_uncompress_belch(file
, ret
);
135 file
->xz_used
= true;
144 static int load_xz(struct kmod_file
*file
)
146 lzma_stream strm
= LZMA_STREAM_INIT
;
150 lzret
= lzma_stream_decoder(&strm
, UINT64_MAX
, LZMA_CONCATENATED
);
151 if (lzret
== LZMA_MEM_ERROR
) {
152 ERR(file
->ctx
, "xz: %s\n", strerror(ENOMEM
));
154 } else if (lzret
!= LZMA_OK
) {
155 ERR(file
->ctx
, "xz: Internal error (bug)\n");
158 ret
= xz_uncompress(&strm
, file
);
163 static void unload_xz(struct kmod_file
*file
)
170 static const char magic_xz
[] = {0xfd, '7', 'z', 'X', 'Z', 0};
174 #define READ_STEP (4 * 1024 * 1024)
175 static int load_zlib(struct kmod_file
*file
)
178 off_t did
= 0, total
= 0;
179 _cleanup_free_
unsigned char *p
= NULL
;
182 file
->gzf
= gzdopen(file
->fd
, "rb");
183 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
;
226 static void unload_zlib(struct kmod_file
*file
)
228 if (file
->gzf
== NULL
)
231 gzclose(file
->gzf
); /* closes file->fd */
234 static const char magic_zlib
[] = {0x1f, 0x8b};
237 static const struct comp_type
{
239 const char *magic_bytes
;
240 const struct file_ops ops
;
243 {sizeof(magic_xz
), magic_xz
, {load_xz
, unload_xz
}},
246 {sizeof(magic_zlib
), magic_zlib
, {load_zlib
, unload_zlib
}},
248 {0, NULL
, {NULL
, NULL
}}
251 static int load_reg(struct kmod_file
*file
)
255 if (fstat(file
->fd
, &st
) < 0)
258 file
->size
= st
.st_size
;
259 file
->memory
= mmap(NULL
, file
->size
, PROT_READ
, MAP_PRIVATE
,
261 if (file
->memory
== MAP_FAILED
)
267 static void unload_reg(struct kmod_file
*file
)
269 munmap(file
->memory
, file
->size
);
272 static const struct file_ops reg_ops
= {
276 struct kmod_elf
*kmod_file_get_elf(struct kmod_file
*file
)
281 file
->elf
= kmod_elf_new(file
->memory
, file
->size
);
285 struct kmod_file
*kmod_file_open(const struct kmod_ctx
*ctx
,
286 const char *filename
)
288 struct kmod_file
*file
= calloc(1, sizeof(struct kmod_file
));
289 const struct comp_type
*itr
;
290 size_t magic_size_max
= 0;
296 file
->fd
= open(filename
, O_RDONLY
|O_CLOEXEC
);
302 for (itr
= comp_types
; itr
->ops
.load
!= NULL
; itr
++) {
303 if (magic_size_max
< itr
->magic_size
)
304 magic_size_max
= itr
->magic_size
;
307 file
->direct
= false;
308 if (magic_size_max
> 0) {
309 char *buf
= alloca(magic_size_max
+ 1);
316 sz
= read_str_safe(file
->fd
, buf
, magic_size_max
+ 1);
317 lseek(file
->fd
, 0, SEEK_SET
);
318 if (sz
!= (ssize_t
)magic_size_max
) {
326 for (itr
= comp_types
; itr
->ops
.load
!= NULL
; itr
++) {
327 if (memcmp(buf
, itr
->magic_bytes
, itr
->magic_size
) == 0)
330 if (itr
->ops
.load
!= NULL
)
331 file
->ops
= &itr
->ops
;
334 if (file
->ops
== NULL
)
335 file
->ops
= ®_ops
;
337 err
= file
->ops
->load(file
);
351 void *kmod_file_get_contents(const struct kmod_file
*file
)
356 off_t
kmod_file_get_size(const struct kmod_file
*file
)
361 bool kmod_file_get_direct(const struct kmod_file
*file
)
366 int kmod_file_get_fd(const struct kmod_file
*file
)
371 void kmod_file_unref(struct kmod_file
*file
)
374 kmod_elf_unref(file
->elf
);
376 file
->ops
->unload(file
);