1 /******************************************************************************
4 * Copyright (c) 2020, longpanda <admin@ventoy.net>
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.
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.
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/>.
21 #define FUSE_USE_VERSION 26
31 typedef unsigned int uint32_t;
33 typedef struct dmtable_entry
37 unsigned long long diskSector
;
40 #define MAX_ENTRY_NUM (1024 * 1024 / sizeof(dmtable_entry))
42 static int verbose
= 0;
43 #define debug(fmt, ...) if(verbose) printf(fmt, ##__VA_ARGS__)
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;
52 static int ventoy_iso_getattr(const char *path
, struct stat
*statinfo
)
58 memset(statinfo
, 0, sizeof(struct stat
));
60 if (path
[0] == '/' && path
[1] == 0)
62 statinfo
->st_mode
= S_IFDIR
| 0755;
63 statinfo
->st_nlink
= 2;
66 else if (strcmp(path
, g_iso_file_name
) == 0)
68 statinfo
->st_mode
= S_IFREG
| 0444;
69 statinfo
->st_nlink
= 1;
70 statinfo
->st_size
= g_iso_file_size
;
78 static int ventoy_iso_readdir
82 fuse_fill_dir_t filler
,
84 struct fuse_file_info
*file
90 if (path
[0] != '/' || path
[1] != 0)
95 filler(buf
, ".", NULL
, 0);
96 filler(buf
, "..", NULL
, 0);
97 filler(buf
, g_iso_file_name
+ 1, NULL
, 0);
102 static int ventoy_iso_open(const char *path
, struct fuse_file_info
*file
)
104 if (strcmp(path
, g_iso_file_name
) != 0)
109 if ((file
->flags
& 3) != O_RDONLY
)
117 static int ventoy_read_iso_sector(uint32_t sector
, uint32_t num
, char *buf
)
120 uint32_t leftSec
= 0;
121 uint32_t readSec
= 0;
123 dmtable_entry
*entry
= NULL
;
125 for (i
= 0; i
< g_disk_entry_num
&& num
> 0; i
++)
127 entry
= g_disk_entry_list
+ i
;
129 if (sector
>= entry
->isoSector
&& sector
< entry
->isoSector
+ entry
->sectorNum
)
131 offset
= (entry
->diskSector
+ (sector
- entry
->isoSector
)) * 512;
133 leftSec
= entry
->sectorNum
- (sector
- entry
->isoSector
);
134 readSec
= (leftSec
> num
) ? num
: leftSec
;
136 pread(g_disk_fd
, buf
, readSec
* 512, offset
);
139 buf
+= readSec
* 512;
147 static int ventoy_iso_read
149 const char *path
, char *buf
,
150 size_t size
, off_t offset
,
151 struct fuse_file_info
*file
163 if(strcmp(path
, g_iso_file_name
) != 0)
168 if (offset
>= g_iso_file_size
)
173 if (offset
+ size
> g_iso_file_size
)
175 size
= g_iso_file_size
- offset
;
179 sector
= offset
/ 512;
185 ventoy_read_iso_sector(sector
, 1, secbuf
);
187 if (leftsize
> align
)
189 memcpy(buf
, secbuf
+ mod
, align
);
197 memcpy(buf
, secbuf
+ mod
, leftsize
);
202 number
= leftsize
/ 512;
203 ventoy_read_iso_sector(sector
, number
, buf
);
206 mod
= leftsize
% 512;
209 ventoy_read_iso_sector(sector
+ number
, 1, secbuf
);
210 memcpy(buf
, secbuf
, mod
);
216 static struct fuse_operations ventoy_op
=
218 .getattr
= ventoy_iso_getattr
,
219 .readdir
= ventoy_iso_readdir
,
220 .open
= ventoy_iso_open
,
221 .read
= ventoy_iso_read
,
224 static int ventoy_parse_dmtable(const char *filename
)
227 char diskname
[128] = {0};
228 char line
[256] = {0};
229 dmtable_entry
*entry
= g_disk_entry_list
;
231 fp
= fopen(filename
, "r");
234 printf("Failed to open file %s\n", filename
);
238 /* read untill the last line */
239 while (fgets(line
, sizeof(line
), fp
) && g_disk_entry_num
< MAX_ENTRY_NUM
)
241 sscanf(line
, "%u %u linear %s %llu",
242 &entry
->isoSector
, &entry
->sectorNum
,
243 diskname
, &entry
->diskSector
);
245 g_iso_file_size
+= (uint64_t)entry
->sectorNum
* 512ULL;
251 if (g_disk_entry_num
>= MAX_ENTRY_NUM
)
253 fprintf(stderr
, "ISO file has too many fragments ( more than %u )\n", MAX_ENTRY_NUM
);
257 debug("iso file size: %llu disk name %s\n", g_iso_file_size
, diskname
);
259 g_disk_fd
= open(diskname
, O_RDONLY
);
262 debug("Failed to open %s\n", diskname
);
269 int main(int argc
, char **argv
)
273 char filename
[512] = {0};
275 /* Avoid to be killed by systemd */
276 if (access("/etc/initrd-release", F_OK
) >= 0)
281 g_iso_file_name
[0] = '/';
283 while ((ch
= getopt(argc
, argv
, "f:s:m:v::t::")) != -1)
287 strncpy(filename
, optarg
, sizeof(filename
) - 1);
291 strncpy(g_mnt_point
, optarg
, sizeof(g_mnt_point
) - 1);
295 strncpy(g_iso_file_name
+ 1, optarg
, sizeof(g_iso_file_name
) - 2);
301 else if (ch
== 't') // for test
307 if (filename
[0] == 0)
309 fprintf(stderr
, "Must input dmsetup table file with -f\n");
313 if (g_mnt_point
[0] == 0)
315 fprintf(stderr
, "Must input mount point with -m\n");
319 if (g_iso_file_name
[1] == 0)
321 strncpy(g_iso_file_name
+ 1, "ventoy.iso", sizeof(g_iso_file_name
) - 2);
324 debug("ventoy fuse iso: %s %s %s\n", filename
, g_iso_file_name
, g_mnt_point
);
326 g_disk_entry_list
= malloc(MAX_ENTRY_NUM
* sizeof(dmtable_entry
));
327 if (NULL
== g_disk_entry_list
)
332 rc
= ventoy_parse_dmtable(filename
);
335 free(g_disk_entry_list
);
339 argv
[1] = g_mnt_point
;
341 rc
= fuse_main(2, argv
, &ventoy_op
, NULL
);
345 free(g_disk_entry_list
);