]>
git.ipfire.org Git - thirdparty/kmod.git/blob - libkmod/libkmod-file.c
2 * libkmod - interface to kernel module operations
4 * Copyright (C) 2011 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"
54 static bool xz_detect(struct kmod_file
*file
)
59 ret
= read(file
->fd
, buf
, sizeof(buf
));
60 if (ret
< 0 || lseek(file
->fd
, 0, SEEK_SET
))
62 return ret
== sizeof(buf
) &&
63 memcmp(buf
, "\xFD""7zXZ\x00", sizeof(buf
)) == 0;
66 static void xz_uncompress_belch(lzma_ret ret
)
70 fprintf(stderr
, "xz: %s\n", strerror(ENOMEM
));
72 case LZMA_FORMAT_ERROR
:
73 fprintf(stderr
, "xz: File format not recognized\n");
75 case LZMA_OPTIONS_ERROR
:
76 fprintf(stderr
, "xz: Unsupported compression options\n");
79 fprintf(stderr
, "xz: File is corrupt\n");
82 fprintf(stderr
, "xz: Unexpected end of input\n");
85 fprintf(stderr
, "xz: Internal error (bug)\n");
90 static int xz_uncompress(lzma_stream
*strm
, struct kmod_file
*file
)
92 uint8_t in_buf
[BUFSIZ
], out_buf
[BUFSIZ
];
93 lzma_action action
= LZMA_RUN
;
99 strm
->next_out
= out_buf
;
100 strm
->avail_out
= sizeof(out_buf
);
103 if (strm
->avail_in
== 0) {
104 ssize_t rdret
= read(file
->fd
, in_buf
, sizeof(in_buf
));
109 strm
->next_in
= in_buf
;
110 strm
->avail_in
= rdret
;
112 action
= LZMA_FINISH
;
114 ret
= lzma_code(strm
, action
);
115 if (strm
->avail_out
== 0 || ret
!= LZMA_OK
) {
116 size_t write_size
= BUFSIZ
- strm
->avail_out
;
117 char *tmp
= realloc(p
, total
+ write_size
);
122 memcpy(tmp
+ total
, out_buf
, write_size
);
125 strm
->next_out
= out_buf
;
126 strm
->avail_out
= BUFSIZ
;
128 if (ret
== LZMA_STREAM_END
)
130 if (ret
!= LZMA_OK
) {
131 xz_uncompress_belch(ret
);
145 static int xz_file_open(struct kmod_file
*file
)
147 lzma_stream strm
= LZMA_STREAM_INIT
;
151 lzret
= lzma_stream_decoder(&strm
, UINT64_MAX
, LZMA_CONCATENATED
);
152 if (lzret
== LZMA_MEM_ERROR
) {
153 fprintf(stderr
, "xz: %s\n", strerror(ENOMEM
));
156 } else if (lzret
!= LZMA_OK
) {
157 fprintf(stderr
, "xz: Internal error (bug)\n");
161 ret
= xz_uncompress(&strm
, file
);
168 #define READ_STEP (4 * 1024 * 1024)
170 static bool check_zlib(struct kmod_file
*file
)
172 uint8_t magic
[2] = {0, 0}, zlibmagic
[2] = {0x1f, 0x8b};
173 size_t done
= 0, todo
= 2;
175 ssize_t r
= read(file
->fd
, magic
+ done
, todo
);
181 else if (errno
== EAGAIN
|| errno
== EINTR
)
186 lseek(file
->fd
, 0, SEEK_SET
);
187 return memcmp(magic
, zlibmagic
, 2) == 0;
189 lseek(file
->fd
, 0, SEEK_SET
);
193 static int zlib_file_open(struct kmod_file
*file
)
196 off_t did
= 0, total
= 0;
197 unsigned char *p
= NULL
;
200 file
->gzf
= gzdopen(file
->fd
, "rb");
201 if (file
->gzf
== NULL
) {
210 void *tmp
= realloc(p
, total
+ READ_STEP
);
219 r
= gzread(file
->gzf
, p
+ did
, total
- did
);
239 static int reg_file_open(struct kmod_file
*file
)
244 if (fstat(file
->fd
, &st
) < 0) {
249 file
->size
= st
.st_size
;
250 file
->memory
= mmap(0, file
->size
, PROT_READ
, MAP_PRIVATE
, file
->fd
, 0);
251 if (file
->memory
== MAP_FAILED
) {
262 struct kmod_file
*kmod_file_open(const char *filename
)
264 struct kmod_file
*file
= calloc(1, sizeof(struct kmod_file
));
270 file
->fd
= open(filename
, O_RDONLY
|O_CLOEXEC
);
278 err
= xz_file_open(file
);
282 if (check_zlib(file
))
283 err
= zlib_file_open(file
);
286 err
= reg_file_open(file
);
298 void *kmod_file_get_contents(const struct kmod_file
*file
)
303 off_t
kmod_file_get_size(const struct kmod_file
*file
)
308 void kmod_file_unref(struct kmod_file
*file
)
317 if (file
->gzf
!= NULL
) {
322 munmap(file
->memory
, file
->size
);