]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - FUSEISO/vtoy_fuse_iso.c
Fix the resolution issue when boot Windows/WinPE in UEFI mode.
[Ventoy.git] / FUSEISO / vtoy_fuse_iso.c
1 /******************************************************************************
2 * vtoy_fuse_iso.c
3 *
4 * Copyright (c) 2020, longpanda <admin@ventoy.net>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 #define FUSE_USE_VERSION 26
22
23 #include <fuse.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <fcntl.h>
30
31 typedef unsigned int uint32_t;
32
33 typedef struct dmtable_entry
34 {
35 uint32_t isoSector;
36 uint32_t sectorNum;
37 unsigned long long diskSector;
38 }dmtable_entry;
39
40 #define MAX_ENTRY_NUM (1024 * 1024 / sizeof(dmtable_entry))
41
42 static int verbose = 0;
43 #define debug(fmt, ...) if(verbose) printf(fmt, ##__VA_ARGS__)
44
45 static int g_disk_fd = -1;
46 static uint64_t g_iso_file_size;
47 static char g_mnt_point[512];
48 static char g_iso_file_name[512];
49 static dmtable_entry *g_disk_entry_list = NULL;
50 static int g_disk_entry_num = 0;
51
52 static int ventoy_iso_getattr(const char *path, struct stat *statinfo)
53 {
54 int ret = -ENOENT;
55
56 if (path && statinfo)
57 {
58 memset(statinfo, 0, sizeof(struct stat));
59
60 if (path[0] == '/' && path[1] == 0)
61 {
62 statinfo->st_mode = S_IFDIR | 0755;
63 statinfo->st_nlink = 2;
64 ret = 0;
65 }
66 else if (strcmp(path, g_iso_file_name) == 0)
67 {
68 statinfo->st_mode = S_IFREG | 0444;
69 statinfo->st_nlink = 1;
70 statinfo->st_size = g_iso_file_size;
71 ret = 0;
72 }
73 }
74
75 return ret;
76 }
77
78 static int ventoy_iso_readdir
79 (
80 const char *path,
81 void *buf,
82 fuse_fill_dir_t filler,
83 off_t offset,
84 struct fuse_file_info *file
85 )
86 {
87 (void)offset;
88 (void)file;
89
90 if (path[0] != '/' || path[1] != 0)
91 {
92 return -ENOENT;
93 }
94
95 filler(buf, ".", NULL, 0);
96 filler(buf, "..", NULL, 0);
97 filler(buf, g_iso_file_name + 1, NULL, 0);
98
99 return 0;
100 }
101
102 static int ventoy_iso_open(const char *path, struct fuse_file_info *file)
103 {
104 if (strcmp(path, g_iso_file_name) != 0)
105 {
106 return -ENOENT;
107 }
108
109 if ((file->flags & 3) != O_RDONLY)
110 {
111 return -EACCES;
112 }
113
114 return 0;
115 }
116
117 static int ventoy_read_iso_sector(uint32_t sector, uint32_t num, char *buf)
118 {
119 uint32_t i = 0;
120 uint32_t leftSec = 0;
121 uint32_t readSec = 0;
122 off_t offset = 0;
123 dmtable_entry *entry = NULL;
124
125 for (i = 0; i < g_disk_entry_num && num > 0; i++)
126 {
127 entry = g_disk_entry_list + i;
128
129 if (sector >= entry->isoSector && sector < entry->isoSector + entry->sectorNum)
130 {
131 offset = (entry->diskSector + (sector - entry->isoSector)) * 512;
132
133 leftSec = entry->sectorNum - (sector - entry->isoSector);
134 readSec = (leftSec > num) ? num : leftSec;
135
136 pread(g_disk_fd, buf, readSec * 512, offset);
137
138 sector += readSec;
139 buf += readSec * 512;
140 num -= readSec;
141 }
142 }
143
144 return 0;
145 }
146
147 static int ventoy_iso_read
148 (
149 const char *path, char *buf,
150 size_t size, off_t offset,
151 struct fuse_file_info *file
152 )
153 {
154 uint32_t mod = 0;
155 uint32_t align = 0;
156 uint32_t sector = 0;
157 uint32_t number = 0;
158 size_t leftsize = 0;
159 char secbuf[512];
160
161 (void)file;
162
163 if(strcmp(path, g_iso_file_name) != 0)
164 {
165 return -ENOENT;
166 }
167
168 if (offset >= g_iso_file_size)
169 {
170 return 0;
171 }
172
173 if (offset + size > g_iso_file_size)
174 {
175 size = g_iso_file_size - offset;
176 }
177
178 leftsize = size;
179 sector = offset / 512;
180
181 mod = offset % 512;
182 if (mod > 0)
183 {
184 align = 512 - mod;
185 ventoy_read_iso_sector(sector, 1, secbuf);
186
187 if (leftsize > align)
188 {
189 memcpy(buf, secbuf + mod, align);
190 buf += align;
191 offset += align;
192 sector++;
193 leftsize -= align;
194 }
195 else
196 {
197 memcpy(buf, secbuf + mod, leftsize);
198 return size;
199 }
200 }
201
202 number = leftsize / 512;
203 ventoy_read_iso_sector(sector, number, buf);
204 buf += number * 512;
205
206 mod = leftsize % 512;
207 if (mod > 0)
208 {
209 ventoy_read_iso_sector(sector + number, 1, secbuf);
210 memcpy(buf, secbuf, mod);
211 }
212
213 return size;
214 }
215
216 static struct fuse_operations ventoy_op =
217 {
218 .getattr = ventoy_iso_getattr,
219 .readdir = ventoy_iso_readdir,
220 .open = ventoy_iso_open,
221 .read = ventoy_iso_read,
222 };
223
224 static int ventoy_parse_dmtable(const char *filename)
225 {
226 FILE *fp = NULL;
227 char diskname[128] = {0};
228 char line[256] = {0};
229 dmtable_entry *entry= g_disk_entry_list;
230
231 fp = fopen(filename, "r");
232 if (NULL == fp)
233 {
234 printf("Failed to open file %s\n", filename);
235 return 1;
236 }
237
238 /* read untill the last line */
239 while (fgets(line, sizeof(line), fp) && g_disk_entry_num < MAX_ENTRY_NUM)
240 {
241 sscanf(line, "%u %u linear %s %llu",
242 &entry->isoSector, &entry->sectorNum,
243 diskname, &entry->diskSector);
244
245 g_iso_file_size += (uint64_t)entry->sectorNum * 512ULL;
246 g_disk_entry_num++;
247 entry++;
248 }
249 fclose(fp);
250
251 if (g_disk_entry_num >= MAX_ENTRY_NUM)
252 {
253 fprintf(stderr, "ISO file has too many fragments ( more than %u )\n", MAX_ENTRY_NUM);
254 return 1;
255 }
256
257 debug("iso file size: %llu disk name %s\n", g_iso_file_size, diskname);
258
259 g_disk_fd = open(diskname, O_RDONLY);
260 if (g_disk_fd < 0)
261 {
262 debug("Failed to open %s\n", diskname);
263 return 1;
264 }
265
266 return 0;
267 }
268
269 int main(int argc, char **argv)
270 {
271 int rc;
272 int ch;
273 char filename[512] = {0};
274
275 /* Avoid to be killed by systemd */
276 if (access("/etc/initrd-release", F_OK) >= 0)
277 {
278 argv[0][0] = '@';
279 }
280
281 g_iso_file_name[0] = '/';
282
283 while ((ch = getopt(argc, argv, "f:s:m:v::t::")) != -1)
284 {
285 if (ch == 'f')
286 {
287 strncpy(filename, optarg, sizeof(filename) - 1);
288 }
289 else if (ch == 'm')
290 {
291 strncpy(g_mnt_point, optarg, sizeof(g_mnt_point) - 1);
292 }
293 else if (ch == 's')
294 {
295 strncpy(g_iso_file_name + 1, optarg, sizeof(g_iso_file_name) - 2);
296 }
297 else if (ch == 'v')
298 {
299 verbose = 1;
300 }
301 else if (ch == 't') // for test
302 {
303 return 0;
304 }
305 }
306
307 if (filename[0] == 0)
308 {
309 fprintf(stderr, "Must input dmsetup table file with -f\n");
310 return 1;
311 }
312
313 if (g_mnt_point[0] == 0)
314 {
315 fprintf(stderr, "Must input mount point with -m\n");
316 return 1;
317 }
318
319 if (g_iso_file_name[1] == 0)
320 {
321 strncpy(g_iso_file_name + 1, "ventoy.iso", sizeof(g_iso_file_name) - 2);
322 }
323
324 debug("ventoy fuse iso: %s %s %s\n", filename, g_iso_file_name, g_mnt_point);
325
326 g_disk_entry_list = malloc(MAX_ENTRY_NUM * sizeof(dmtable_entry));
327 if (NULL == g_disk_entry_list)
328 {
329 return 1;
330 }
331
332 rc = ventoy_parse_dmtable(filename);
333 if (rc)
334 {
335 free(g_disk_entry_list);
336 return rc;
337 }
338
339 argv[1] = g_mnt_point;
340 argv[2] = NULL;
341 rc = fuse_main(2, argv, &ventoy_op, NULL);
342
343 close(g_disk_fd);
344
345 free(g_disk_entry_list);
346 return rc;
347 }
348