]> git.ipfire.org Git - thirdparty/kmod.git/blob - libkmod/libkmod-file.c
99ff3f2abe9c10e428de60bfb09c5ea9e46c3aab
[thirdparty/kmod.git] / libkmod / libkmod-file.c
1 /*
2 * libkmod - interface to kernel module operations
3 *
4 * Copyright (C) 2011 ProFUSION embedded systems
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <sys/mman.h>
28 #include <unistd.h>
29
30 #include "libkmod.h"
31 #include "libkmod-private.h"
32
33 #ifdef ENABLE_ZLIB
34 #include <zlib.h>
35 #endif
36
37 struct kmod_file {
38 #ifdef ENABLE_ZLIB
39 gzFile gzf;
40 #endif
41 int fd;
42 off_t size;
43 void *memory;
44 };
45
46 #ifdef ENABLE_ZLIB
47 #define READ_STEP (4 * 1024 * 1024)
48
49 static bool check_zlib(struct kmod_file *file)
50 {
51 uint8_t magic[2] = {0, 0}, zlibmagic[2] = {0x1f, 0x8b};
52 size_t done = 0, todo = 2;
53 while (todo > 0) {
54 ssize_t r = read(file->fd, magic + done, todo);
55 if (r > 0){
56 todo -= r;
57 done += r;
58 } else if (r == 0)
59 goto error;
60 else if (errno == EAGAIN || errno == EINTR)
61 continue;
62 else
63 goto error;
64 }
65 lseek(file->fd, 0, SEEK_SET);
66 return memcmp(magic, zlibmagic, 2) == 0;
67 error:
68 lseek(file->fd, 0, SEEK_SET);
69 return false;
70 }
71
72 static int zlib_file_open(struct kmod_file *file)
73 {
74 int err = 0;
75 off_t did = 0, total = 0;
76 unsigned char *p = NULL;
77
78 errno = 0;
79 file->gzf = gzdopen(file->fd, "rb");
80 if (file->gzf == NULL) {
81 close(file->fd);
82 return -errno;
83 }
84
85 for (;;) {
86 int r;
87
88 if (did == total) {
89 void *tmp = realloc(p, total + READ_STEP);
90 if (tmp == NULL) {
91 err = -errno;
92 goto error;
93 }
94 total += READ_STEP;
95 p = tmp;
96 }
97
98 r = gzread(file->gzf, p + did, total - did);
99 if (r == 0)
100 break;
101 else if (r < 0) {
102 err = -errno;
103 goto error;
104 }
105 did += r;
106 }
107
108 file->memory = p;
109 file->size = did;
110 return 0;
111 error:
112 free(p);
113 gzclose(file->gzf);
114 return err;
115 }
116 #endif
117
118 static int reg_file_open(struct kmod_file *file)
119 {
120 struct stat st;
121 int err = 0;
122
123 if (fstat(file->fd, &st) < 0) {
124 err = -errno;
125 goto error;
126 }
127
128 file->size = st.st_size;
129 file->memory = mmap(0, file->size, PROT_READ, MAP_PRIVATE, file->fd, 0);
130 if (file->memory == MAP_FAILED) {
131 err = -errno;
132 goto error;
133 }
134
135 return 0;
136 error:
137 close(file->fd);
138 return err;
139 }
140
141 struct kmod_file *kmod_file_open(const char *filename)
142 {
143 struct kmod_file *file = calloc(1, sizeof(struct kmod_file));
144 int err;
145
146 if (file == NULL)
147 return NULL;
148
149 file->fd = open(filename, O_RDONLY|O_CLOEXEC);
150 if (file->fd < 0) {
151 err = -errno;
152 goto error;
153 }
154
155 #ifdef ENABLE_ZLIB
156 if (check_zlib(file))
157 err = zlib_file_open(file);
158 else
159 #endif
160 err = reg_file_open(file);
161
162 error:
163 if (err < 0) {
164 free(file);
165 errno = -err;
166 return NULL;
167 }
168
169 return file;
170 }
171
172 void *kmod_file_get_contents(const struct kmod_file *file)
173 {
174 return file->memory;
175 }
176
177 off_t kmod_file_get_size(const struct kmod_file *file)
178 {
179 return file->size;
180 }
181
182 void kmod_file_unref(struct kmod_file *file)
183 {
184 #ifdef ENABLE_ZLIB
185 if (file->gzf != NULL) {
186 free(file->memory);
187 gzclose(file->gzf);
188 } else {
189 #endif
190 munmap(file->memory, file->size);
191 close(file->fd);
192 #ifdef ENABLE_ZLIB
193 }
194 #endif
195 free(file);
196 }