1 
2 /***************************************************************************
3  *                    __            __ _ ___________                       *
4  *                    \ \          / /| |____   ____|                      *
5  *                     \ \        / / | |    | |                           *
6  *                      \ \  /\  / /  | |    | |                           *
7  *                       \ \/  \/ /   | |    | |                           *
8  *                        \  /\  /    | |    | |                           *
9  *                         \/  \/     |_|    |_|                           *
10  *                                                                         *
11  *                           Wiimms ISO Tools                              *
12  *                         http://wit.wiimm.de/                            *
13  *                                                                         *
14  ***************************************************************************
15  *                                                                         *
16  *   This file is part of the WIT project.                                 *
17  *   Visit http://wit.wiimm.de/ for project details and sources.           *
18  *                                                                         *
19  *   Copyright (c) 2009-2013 by Dirk Clemens <wiimm@wiimm.de>              *
20  *                                                                         *
21  ***************************************************************************
22  *                                                                         *
23  *   This program is free software; you can redistribute it and/or modify  *
24  *   it under the terms of the GNU General Public License as published by  *
25  *   the Free Software Foundation; either version 2 of the License, or     *
26  *   (at your option) any later version.                                   *
27  *                                                                         *
28  *   This program is distributed in the hope that it will be useful,       *
29  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
30  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
31  *   GNU General Public License for more details.                          *
32  *                                                                         *
33  *   See file gpl-2.0.txt or http://www.gnu.org/licenses/gpl-2.0.txt       *
34  *                                                                         *
35  ***************************************************************************/
36 
37 #define _GNU_SOURCE 1
38 #define FUSE_USE_VERSION  25
39 
40 #include <sys/wait.h>
41 
42 #include <fuse.h>
43 #include <pthread.h>
44 #include <errno.h>
45 #include <ctype.h>
46 
47 #include "debug.h"
48 #include "version.h"
49 #include "lib-std.h"
50 #include "lib-sf.h"
51 #include "titles.h"
52 #include "iso-interface.h"
53 #include "wbfs-interface.h"
54 
55 #include "ui-wfuse.c"
56 #include "logo.inc"
57 
58 //
59 ///////////////////////////////////////////////////////////////////////////////
60 
61 #define TITLE WFUSE_SHORT ": " WFUSE_LONG " v" VERSION " r" REVISION \
62 	" " SYSTEM " - " AUTHOR " - " DATE
63 
64 #ifndef ENOATTR
65     #define ENOATTR ENOENT
66 #endif
67 
68 ///////////////////////////////////////////////////////////////////////////////
69 // http://fuse.sourceforge.net/
70 // http://sourceforge.net/apps/mediawiki/fuse/index.php?title=API
71 ///////////////////////////////////////////////////////////////////////////////
72 
73 typedef enum enumOpenMode
74 {
75 	OMODE_ISO,
76 	OMODE_WBFS_ISO,
77 	OMODE_WBFS
78 
79 } enumMode;
80 
81 enumMode open_mode = OMODE_ISO;
82 
83 bool is_wbfs		= false;
84 bool is_iso		= false;
85 bool is_fst		= false;
86 bool is_wbfs_iso	= false;
87 int  wbfs_slot		= -1;
88 
89 ///////////////////////////////////////////////////////////////////////////////
90 
91 typedef struct fuse_file_info fuse_file_info;
92 
93 static bool opt_umount		= false;
94 static bool opt_lazy		= false;
95 static bool opt_create		= false;
96 static bool opt_remount		= false;
97 static char * source_file	= 0;
98 static char * mount_point	= 0;
99 
100 static SuperFile_t main_sf;
101 static WBFS_t wbfs;
102 
103 static struct stat stat_dir;
104 static struct stat stat_file;
105 static struct stat stat_link;
106 
107 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
108 
109 //
110 ///////////////////////////////////////////////////////////////////////////////
111 ///////////////			    args			///////////////
112 ///////////////////////////////////////////////////////////////////////////////
113 
114 #define MAX_WBFUSE_ARG 100
115 static char * wbfuse_argv[MAX_WBFUSE_ARG];
116 static int wbfuse_argc = 0;
117 
118 //-----------------------------------------------------------------------------
119 
add_arg(char * arg1,char * arg2)120 static void add_arg ( char * arg1, char * arg2 )
121 {
122     if (arg1)
123     {
124 	if ( wbfuse_argc == MAX_WBFUSE_ARG )
125 	    exit(ERROR0(ERR_SYNTAX,"To many options."));
126 	wbfuse_argv[wbfuse_argc++] = arg1;
127     }
128 
129     if (arg2)
130 	add_arg(arg2,0);
131 }
132 
133 //
134 ///////////////////////////////////////////////////////////////////////////////
135 ///////////////			built in help			///////////////
136 ///////////////////////////////////////////////////////////////////////////////
137 
help_exit()138 static void help_exit()
139 {
140     fputs( TITLE "\n", stdout );
141     PrintHelpCmd(&InfoUI,stdout,0,0,0,0);
142     exit(ERR_OK);
143 }
144 
145 ///////////////////////////////////////////////////////////////////////////////
146 
help_fuse_exit()147 static void help_fuse_exit()
148 {
149     fputs( TITLE "\n", stdout );
150     add_arg("--help",0);
151     static struct fuse_operations wfuse_oper = {0};
152     fuse_main(wbfuse_argc,wbfuse_argv,&wfuse_oper);
153     exit(ERR_OK);
154 }
155 
156 ///////////////////////////////////////////////////////////////////////////////
157 
version_exit()158 static void version_exit()
159 {
160     fputs( TITLE "\n", stdout );
161     add_arg("--version",0);
162     static struct fuse_operations wfuse_oper = {0};
163     fuse_main(wbfuse_argc,wbfuse_argv,&wfuse_oper);
164     exit(ERR_OK);
165 }
166 
167 ///////////////////////////////////////////////////////////////////////////////
168 
hint_exit(enumError stat)169 static void hint_exit ( enumError stat )
170 {
171     fprintf(stderr,
172 	"-> Type '%s -h' (pipe it to a pager like 'less') for more help.\n\n",
173 	progname );
174     exit(stat);
175 }
176 
177 ///////////////////////////////////////////////////////////////////////////////
178 ///////////////////////////////////////////////////////////////////////////////
179 
CheckOptions(int argc,char ** argv)180 static enumError CheckOptions ( int argc, char ** argv )
181 {
182     int err = 0;
183     for(;;)
184     {
185       const int opt_stat = getopt_long(argc,argv,OptionShort,OptionLong,0);
186       if ( opt_stat == -1 )
187 	break;
188 
189       RegisterOptionByName(&InfoUI,opt_stat,1,false);
190 
191       switch ((enumGetOpt)opt_stat)
192       {
193 	case GO__ERR:		err++; break;
194 
195 	case GO_VERSION:	version_exit();
196 	case GO_HELP:
197 	case GO_XHELP:		help_exit();
198 	case GO_WIDTH:		err += ScanOptWidth(optarg); break;
199 	case GO_QUIET:		verbose = verbose > -1 ? -1 : verbose - 1; break;
200 	case GO_VERBOSE:	verbose = verbose <  0 ?  0 : verbose + 1; break;
201 	case GO_IO:		ScanIOMode(optarg); break;
202 
203 	case GO_HELP_FUSE:	help_fuse_exit();
204 	case GO_OPTION:		add_arg("-o",optarg); break;
205 	case GO_ALLOW_OTHER:	add_arg("-o","allow_other"); break;
206 	case GO_PARAM:		add_arg(optarg,0); break;
207 	case GO_UMOUNT:		opt_umount = true; break;
208 	case GO_LAZY:		opt_lazy = true; break;
209 	case GO_CREATE:		opt_create = true; break;
210 	case GO_REMOUNT:	opt_remount = true; break;
211       }
212     }
213  #ifdef DEBUG
214     DumpUsedOptions(&InfoUI,TRACE_FILE,11);
215  #endif
216 
217     return err ? ERR_SYNTAX : ERR_OK;
218 }
219 
220 //
221 ///////////////////////////////////////////////////////////////////////////////
222 ///////////////			    mutex			///////////////
223 ///////////////////////////////////////////////////////////////////////////////
224 
lock_mutex()225 static void lock_mutex()
226 {
227     int err = pthread_mutex_lock(&mutex);
228     if (err)
229 	TRACE("MUTEX LOCK ERR %u\n",err);
230 }
231 
232 //-----------------------------------------------------------------------------
233 
unlock_mutex()234 static void unlock_mutex()
235 {
236     int err = pthread_mutex_unlock(&mutex);
237     if (err)
238 	TRACE("MUTEX UNLOCK ERR %u\n",err);
239 }
240 
241 //
242 ///////////////////////////////////////////////////////////////////////////////
243 ///////////////			struct SlotInfo_t		///////////////
244 ///////////////////////////////////////////////////////////////////////////////
245 
246 typedef struct SlotInfo_t
247 {
248     char		id6[7];		// ID6 of image
249     ccp			fname;		// normalized filename
250     time_t		atime;		// atime of image
251     time_t		mtime;		// mtime of image
252     time_t		ctime;		// ctime of image
253 
254 } SlotInfo_t;
255 
256 static int n_slots = 0;
257 static SlotInfo_t * slot_info = 0;
258 
259 //
260 ///////////////////////////////////////////////////////////////////////////////
261 ///////////////			struct DiscFile_t		///////////////
262 ///////////////////////////////////////////////////////////////////////////////
263 
264 typedef struct DiscFile_t
265 {
266     bool		used;		// false: entry not used
267     uint		lock_count;	// number of locks
268     time_t		timestamp;	// timestamp of last usage
269 
270     int			slot;		// -1 or slot index of WBFS
271     WBFS_t		* wbfs;		// NULL or wbfs
272     SuperFile_t 	* sf;		// NULL or file pointer
273     wd_disc_t		* disc;		// NULL or disc pointer
274     volatile WiiFst_t	* fst;		// NULL or collected files
275 
276     struct stat		stat_dir;	// template for directories
277     struct stat		stat_file;	// template for regular files
278     struct stat		stat_link;	// template for soft links
279 
280 } DiscFile_t;
281 
282 #define MAX_DISC_FILES		 50
283 #define GOOD_DISC_FILES		  5
284 #define DISC_FILES_TIMEOUT1	 15
285 #define DISC_FILES_TIMEOUT2	 60
286 
287 DiscFile_t dfile[MAX_DISC_FILES];
288 int n_dfile = 0;
289 
290 ///////////////////////////////////////////////////////////////////////////////
291 
get_disc_file(uint slot)292 static DiscFile_t * get_disc_file ( uint slot )
293 {
294     DASSERT( slot < n_slots );
295     DiscFile_t * df;
296     DiscFile_t * end_dfile = dfile + MAX_DISC_FILES;
297 
298     lock_mutex();
299 
300     //----- try to find 'slot'
301 
302     for ( df = dfile; df < end_dfile; df++ )
303 	if ( df->used && df->slot == slot )
304 	{
305 	    df->lock_count++;
306 	    TRACE(">>D<< ALLOC DISC #%zu, slot=%d, lock=%d, n=%d/%d\n",
307 		df-dfile, df->slot, df->lock_count, n_dfile, MAX_DISC_FILES );
308 	    unlock_mutex();
309 	    return df;
310 	}
311 
312     //----- not found: find first free slot && close timeouts
313 
314     time_t ref_time = time(0)
315 		- ( n_dfile < GOOD_DISC_FILES
316 			? DISC_FILES_TIMEOUT1 : DISC_FILES_TIMEOUT2 );
317 
318     DiscFile_t * found_df = 0;
319     for ( df = dfile; df < end_dfile; df++ )
320     {
321 	if ( df->used
322 	    && !df->lock_count
323 	    && ( n_dfile == MAX_DISC_FILES || df->timestamp < ref_time ) )
324 	{
325 	    TRACE(">>D<< CLOSE DISC #%zu, slot=%d, lock=%d, n=%d/%d\n",
326 		df-dfile, df->slot, df->lock_count, n_dfile, MAX_DISC_FILES );
327 	    if (df->fst)
328 	    {
329 		WiiFst_t * fst = (WiiFst_t*)df->fst; // avoid volatile warnings
330 	        df->fst = 0;
331 	        ResetFST(fst);
332 	        FREE(fst);
333 	    }
334 	    ResetWBFS(df->wbfs);
335 	    FREE(df->wbfs);
336 	    memset(df,0,sizeof(df));
337 	    n_dfile--;
338 	}
339 
340 	if ( !found_df && !df->used )
341 	    found_df = df;
342     }
343 
344     //----- open new file
345 
346     if (found_df)
347     {
348 	memset(found_df,0,sizeof(found_df));
349 	WBFS_t * wbfs = MALLOC(sizeof(*wbfs));
350 	InitializeWBFS(wbfs);
351 	enumError err = OpenWBFS(wbfs,source_file,false,true,0);
352 	wbfs->cache_candidate = false;
353 	if (!err)
354 	{
355 	    err = OpenWDiscSlot(wbfs,slot,false);
356 	    if (!err)
357 		err = OpenWDiscSF(wbfs);
358 	}
359 
360 	wd_disc_t * disc = err ? 0 : OpenDiscSF(wbfs->sf,true,true);
361 	TRACE(">>D<< disc=%p\n",disc);
362 	if (!disc)
363 	{
364 	    ResetWBFS(wbfs);
365 	    FREE(wbfs);
366 	    found_df = 0;
367 	}
368 	else
369 	{
370 	    wd_calc_disc_status(disc,true);
371 
372 	    found_df->used		= true;
373 	    found_df->lock_count	= 1;
374 	    found_df->slot		= slot;
375 	    found_df->wbfs		= wbfs;
376 	    found_df->sf		= wbfs->sf;
377 	    found_df->disc		= disc;
378 
379 	    memcpy(&found_df->stat_dir, &stat_dir, sizeof(found_df->stat_dir ));
380 	    memcpy(&found_df->stat_file,&stat_file,sizeof(found_df->stat_file));
381 	    memcpy(&found_df->stat_link,&stat_link,sizeof(found_df->stat_link));
382 
383 	    DASSERT(slot_info);
384 	    SlotInfo_t * si = slot_info + slot;
385 	    found_df  ->stat_dir .st_atime =
386 	      found_df->stat_file.st_atime =
387 	      found_df->stat_link.st_atime = si->atime;
388 	    found_df  ->stat_dir .st_mtime =
389 	      found_df->stat_file.st_mtime =
390 	      found_df->stat_link.st_mtime = si->mtime;
391 	    found_df  ->stat_dir .st_ctime =
392 	      found_df->stat_file.st_ctime =
393 	      found_df->stat_link.st_ctime = si->ctime;
394 
395 	    n_dfile++;
396 
397 	    TRACE(">>D<< OPEN DISC #%zu, slot=%d, lock=%d, n=%d/%d\n",
398 		found_df-dfile, found_df->slot, found_df->lock_count,
399 		n_dfile, MAX_DISC_FILES );
400 	}
401     }
402 
403     unlock_mutex();
404 
405     return found_df;
406 }
407 
408 ///////////////////////////////////////////////////////////////////////////////
409 
free_disc_file(DiscFile_t * df)410 static void free_disc_file ( DiscFile_t * df )
411 {
412     if (df)
413     {
414 	DASSERT(df->used);
415 	DASSERT(df->lock_count);
416 	TRACE(">>D<< FREE DISC #%zu, slot=%d, lock=%d, n=%d/%d\n",
417 		df-dfile, df->slot, df->lock_count, n_dfile, MAX_DISC_FILES );
418 
419 	lock_mutex();
420 	df->lock_count--;
421 	df->timestamp = time(0);
422 	unlock_mutex();
423     }
424 }
425 
426 ///////////////////////////////////////////////////////////////////////////////
427 
get_fst(DiscFile_t * df)428 static WiiFst_t * get_fst ( DiscFile_t * df )
429 {
430     DASSERT(df);
431     WiiFst_t * fst = (WiiFst_t*)df->fst; // cast to avaoid volatile warnings
432     if (!fst)
433     {
434 	lock_mutex();
435 	fst = (WiiFst_t*)df->fst;
436 	if (!fst)
437 	{
438 	    fst = MALLOC(sizeof(*fst));
439 	    InitializeFST(fst);
440 	    CollectFST(fst,df->disc,0,false,0,WD_IPM_SLASH,true);
441 	    SortFST(fst,SORT_NAME,SORT_NAME);
442 	    df->fst = fst;
443 	}
444 	unlock_mutex();
445     }
446     return fst;
447 }
448 
449 ///////////////////////////////////////////////////////////////////////////////
450 
get_fst_pointer(WiiFstPart_t ** found_part,WiiFstFile_t ** found_file,WiiFstFile_t ** list_end,DiscFile_t * df,wd_part_t * part,ccp subpath)451 static int get_fst_pointer // return relevant subpath length; -1 on error
452 (
453     WiiFstPart_t	** found_part,	// not NULL: store found partition
454     WiiFstFile_t	** found_file,	// not NULL: store first founds item
455     WiiFstFile_t	** list_end,	// not NULL: store end of list
456     DiscFile_t		* df,		// valid disc file
457     wd_part_t		* part,		// NULL or relevant partition
458     ccp			subpath		// NULL or subpath
459 )
460 {
461     DASSERT(df);
462     TRACE("get_fst_pointer(...,%s)\n",subpath);
463 
464     if (found_part)
465 	*found_part = 0;
466     if (found_file)
467 	*found_file = 0;
468     if (list_end)
469 	*list_end = 0;
470     if (!part)
471 	return -1;
472     if (!subpath)
473 	subpath = "";
474 
475     WiiFst_t * fst = get_fst(df);
476     if (fst)
477     {
478 	WiiFstPart_t *fst_part, *part_end = fst->part + fst->part_used;
479 	for ( fst_part = fst->part; fst_part < part_end; fst_part++ )
480 	    if ( part == fst_part->part )
481 	    {
482 		noTRACE("PART-FOUND:\n");
483 		// [[2do]] binary search
484 
485 		int slen = strlen(subpath);
486 		WiiFstFile_t * ptr = fst_part->file;
487 		WiiFstFile_t * end = ptr + fst_part->file_used;
488 		for ( ; ptr < end; ptr++ )
489 		{
490 		    noTRACE("CHECK: %s\n",ptr->path);
491 		    if (!memcmp(subpath,ptr->path,slen))
492 		    {
493 			const char ch = ptr->path[slen];
494 			noTRACE("FOUND[%02x]: %s\n",ch,ptr->path);
495 			if ( !ch || ch == '/' )
496 			{
497 			    if (found_part)
498 				*found_part = fst_part;
499 			    if (found_file)
500 				*found_file = ptr;
501 			    if (list_end)
502 				*list_end = end;
503 			    return slen;
504 			}
505 		    }
506 		}
507 		break;
508 	    }
509     }
510     return -1;
511 }
512 
513 //
514 ///////////////////////////////////////////////////////////////////////////////
515 ///////////////			info helpers			///////////////
516 ///////////////////////////////////////////////////////////////////////////////
517 
518 #define INFO_SIZE 500
519 
520 ///////////////////////////////////////////////////////////////////////////////
521 
print_root_info(char * pbuf,size_t bufsize)522 static size_t print_root_info
523 (
524     char		* pbuf,
525     size_t		bufsize
526 )
527 {
528     DASSERT(pbuf);
529 
530     return snprintf( pbuf, bufsize,
531 		"is-iso=%u\n"
532 		"is-wbfs=%u\n"
533 		"file-type=%s\n"
534 		"file-size=%llu\n"
535 		"split-count=%u\n"
536 		,is_iso
537 		,is_wbfs
538 		,oft_info[main_sf.iod.oft].name
539 		,(u64)main_sf.f.st.st_size
540 		,main_sf.f.split_used > 1 ? main_sf.f.split_used : 0
541 		);
542 }
543 
544 ///////////////////////////////////////////////////////////////////////////////
545 
print_wbfs_info(char * pbuf,size_t bufsize)546 static size_t print_wbfs_info
547 (
548     char		* pbuf,
549     size_t		bufsize
550 )
551 {
552     DASSERT(pbuf);
553     wbfs_t * w = wbfs.wbfs;
554     return !is_wbfs || !w
555 	? 0
556 	: snprintf( pbuf, bufsize,
557 		"hd-sector-size=%u\n"
558 		"n-hd-sectors=%u\n"
559 
560 		"wii-sector-size=%u\n"
561 		"wii-sectors=%u\n"
562 		"wii-sectors-per-disc=%u\n"
563 
564 		"wbfs-sector-size=%u\n"
565 		"wbfs-sectors=%u\n"
566 		"wbfs-sectors-per-disc=%u\n"
567 
568 		"part-lba=%u\n"
569 
570 		"used-slots=%u\n"
571 		"free-slots=%u\n"
572 		"total-slots=%u\n"
573 
574 		"used-size-mib=%u\n"
575 		"free-size-mib=%u\n"
576 		"total-size-mib=%u\n"
577 
578 		,w->hd_sec_sz
579 		,w->n_hd_sec
580 
581 		,w->wii_sec_sz
582 		,w->n_wii_sec
583 		,w->n_wii_sec_per_disc
584 
585 		,w->wbfs_sec_sz
586 		,w->n_wbfs_sec
587 		,w->n_wbfs_sec_per_disc
588 
589 		,w->part_lba
590 
591 		,wbfs.used_discs
592 		,wbfs.free_discs
593 		,wbfs.total_discs
594 
595 		,wbfs.used_mib
596 		,wbfs.free_mib
597 		,wbfs.total_mib
598 		);
599 }
600 
601 ///////////////////////////////////////////////////////////////////////////////
602 
print_iso_info(DiscFile_t * df,char * pbuf,size_t bufsize)603 static size_t print_iso_info
604 (
605     DiscFile_t		* df,
606     char		* pbuf,
607     size_t		bufsize
608 )
609 {
610     DASSERT(df);
611     DASSERT(pbuf);
612     char * dest = pbuf;
613     //char * end = pbuf + bufsize - 1;
614 
615     wd_disc_t * disc = df->disc;
616     if (disc)
617     {
618 	char id[7];
619 	wd_print_id(&disc->dhead.disc_id,6,id);
620 	dest += snprintf( pbuf, bufsize,
621 		"disc-id=%s\n"
622 		"disc-title=%.64s\n"
623 		"db-title=%s\n"
624 		"n-part=%u\n"
625 		,id
626 		,(ccp)disc->dhead.disc_title
627 		,GetTitle(id,"")
628 		,disc->n_part
629 		);
630     }
631 
632     *dest = 0;
633     return dest - pbuf;
634 }
635 
636 ///////////////////////////////////////////////////////////////////////////////
637 
get_sign_info(cert_stat_t stat)638 static ccp get_sign_info ( cert_stat_t stat )
639 {
640     if ( stat & CERT_F_HASH_FAILED )	return "not signed";
641     if ( stat & CERT_F_HASH_FAKED )	return "fake signed";
642     if ( stat & CERT_F_HASH_OK )	return "well signed";
643     return "";
644 }
645 
646 ///////////////////////////////////////////////////////////////////////////////
647 
print_part_info(wd_part_t * part,char * pbuf,size_t bufsize)648 static size_t print_part_info
649 (
650     wd_part_t		* part,
651     char		* pbuf,
652     size_t		bufsize
653 )
654 {
655     DASSERT(part);
656     DASSERT(pbuf);
657 
658     return snprintf( pbuf, bufsize,
659 		"index=%u\n"
660 		"ptab=%u\n"
661 		"ptab-index=%u\n"
662 		"type=%x\n"
663 		"size=%llu\n"
664 
665 		"is-overlay=%u\n"
666 		"is-gc=%u\n"
667 		"is-encrypted=%u\n"
668 		"is-decrypted=%u\n"
669 		"is-skeleton=%u\n"
670 		"is-scrubbed=%u\n"
671 		"ticket-signed=%s\n"
672 		"tmd-signed=%s\n"
673 
674 		"start-sector=%u\n"
675 		"end-sector=%u\n"
676 
677 		"fst-entries=%u\n"
678 		"virtual-dirs=%u\n"
679 		"virtual-files=%u\n"
680 
681 		,part->index
682 		,part->ptab_index
683 		,part->ptab_part_index
684 		,part->part_type
685 		,part->part_size
686 
687 		,part->is_overlay
688 		,part->is_gc
689 		,0 != ( part->sector_stat & WD_SS_ENCRYPTED )
690 		,0 != ( part->sector_stat & WD_SS_DECRYPTED )
691 		,0 != ( part->sector_stat & WD_SS_F_SKELETON )
692 		,0 != ( part->sector_stat & WD_SS_F_SCRUBBED )
693 
694 		,get_sign_info(part->cert_tik_stat)
695 		,get_sign_info(part->cert_tmd_stat)
696 
697 		,part->data_sector
698 		,part->end_sector
699 
700 		,part->fst_n
701 		,part->fst_dir_count
702 		,part->fst_file_count
703 		);
704 }
705 
706 //
707 ///////////////////////////////////////////////////////////////////////////////
708 ///////////////			analyze_path()			///////////////
709 ///////////////////////////////////////////////////////////////////////////////
710 
711 typedef enum enumAnaPath
712 {
713     AP_UNKNOWN,
714 
715     AP_ROOT,
716     AP_ROOT_INFO,
717 
718     AP_ISO,
719     AP_ISO_DISC,
720     AP_ISO_INFO,
721     AP_ISO_PART,
722 
723     AP_ISO_PART_DATA,
724     AP_ISO_PART_UPDATE,
725     AP_ISO_PART_CHANNEL,
726     AP_ISO_PART_MAIN,
727 
728     AP_WBFS,
729     AP_WBFS_SLOT,
730     AP_WBFS_ID,
731     AP_WBFS_TITLE,
732     AP_WBFS_INFO,
733 
734 } enumAnaPath;
735 
736 //-----------------------------------------------------------------------------
737 
738 typedef struct AnaPath_t
739 {
740     enumAnaPath	ap;
741     int		len;
742     ccp		path;
743 
744 } AnaPath_t;
745 
746 //-----------------------------------------------------------------------------
747 
748 #define DEF_AP(a,s) { a, sizeof(s)-1, s }
749 
750 static AnaPath_t ana_path_tab_root[] =
751 {
752     DEF_AP( AP_ISO,		"/iso" ),
753     DEF_AP( AP_WBFS_SLOT,	"/wbfs/slot" ),
754     DEF_AP( AP_WBFS_ID,		"/wbfs/id" ),
755     DEF_AP( AP_WBFS_TITLE,	"/wbfs/title" ),
756     DEF_AP( AP_WBFS_INFO,	"/wbfs/info.txt" ),
757     DEF_AP( AP_WBFS,		"/wbfs" ),
758     DEF_AP( AP_ROOT_INFO,	"/info.txt" ),
759     {0,0,0}
760 };
761 
762 static AnaPath_t ana_path_tab_iso[] =
763 {
764     DEF_AP( AP_ISO_DISC,	"/disc.iso" ),
765     DEF_AP( AP_ISO_INFO,	"/info.txt" ),
766     DEF_AP( AP_ISO_PART_DATA,	"/part/data" ),
767     DEF_AP( AP_ISO_PART_UPDATE,	"/part/update" ),
768     DEF_AP( AP_ISO_PART_CHANNEL,"/part/channel" ),
769     DEF_AP( AP_ISO_PART_MAIN,	"/part/main" ),
770     DEF_AP( AP_ISO_PART,	"/part" ),
771     {0,0,0}
772 };
773 
774 //-----------------------------------------------------------------------------
775 
analyze_path(enumAnaPath * stat,ccp path,AnaPath_t * tab)776 static ccp analyze_path ( enumAnaPath * stat, ccp path, AnaPath_t * tab )
777 {
778     TRACE("analyze_path(%p,%s,%p)\n",stat,path,tab);
779     DASSERT(tab);
780     if (!path)
781 	path = "";
782     const int plen = strlen(path);
783 
784     for ( ; tab->path; tab++ )
785     {
786 	if ( ( plen == tab->len || plen > tab->len && path[tab->len] == '/' )
787 	    && !memcmp(path,tab->path,tab->len) )
788 	{
789 	    TRACE(" - found: id=%u, len=%u, sub=%s\n",tab->ap,tab->len,path+tab->len);
790 	    if (stat)
791 		*stat = tab->ap;
792 	    return path + tab->len;
793 	}
794     }
795 
796     if ( !*path || !strcmp(path,"/") )
797     {
798 	TRACE(" - root\n");
799 	if (stat)
800 	    *stat = AP_ROOT;
801 	if (*path)
802 	    path++;
803     }
804     else if (stat)
805 	*stat = AP_UNKNOWN;
806 
807     return path;
808 }
809 
810 //
811 ///////////////////////////////////////////////////////////////////////////////
812 ///////////////			analyze_part()			///////////////
813 ///////////////////////////////////////////////////////////////////////////////
814 
analyze_part(ccp * subpath,ccp path,wd_disc_t * disc)815 static wd_part_t * analyze_part
816 (
817     ccp		* subpath,	// result
818     ccp		path,		// source path
819     wd_disc_t	* disc		// disc
820 )
821 {
822     TRACE("analyze_part(%s)\n",path);
823     DASSERT(path);
824 
825     wd_part_t * found_part = 0;
826 
827     if ( disc
828 	 && path[0] == '/'
829 	 && path[1] >= '0' && path[1] < '0' + WII_MAX_PTAB
830 	 && path[2] == '.' )
831     {
832 	//TRACELINE;
833 	char * end;
834 	const uint p_idx = strtoul(path+3,&end,10);
835 	if ( end > path+3 && ( !*end || *end == '/' ))
836 	{
837 	    const uint t_idx = path[1] - '0';
838 	    TRACE(" - check %u.%u\n",t_idx,p_idx);
839 	    int ip;
840 	    for ( ip = 0; ip < disc->n_part; ip++ )
841 	    {
842 		wd_part_t * part = disc->part + ip;
843 		TRACE(" - cmp %u.%u\n",part->ptab_index,part->ptab_part_index);
844 		if ( t_idx == part->ptab_index && p_idx == part->ptab_part_index )
845 		{
846 		    TRACE(" - found %u.%u\n",t_idx,p_idx);
847 		    path = end;
848 		    found_part = part;
849 		    break;
850 		}
851 	    }
852 	}
853     }
854 
855     if (subpath)
856 	*subpath = path;
857     return found_part;
858 }
859 
860 //
861 ///////////////////////////////////////////////////////////////////////////////
862 ///////////////			analyze_slot()			///////////////
863 ///////////////////////////////////////////////////////////////////////////////
864 
analyze_slot(ccp * subpath,ccp path)865 static int analyze_slot
866 (
867     ccp		* subpath,	// result
868     ccp		path		// source path
869 )
870 {
871     TRACE("analyze_slot(%s)\n",path);
872     DASSERT(path);
873 
874     int found_slot = -1;
875     wbfs_t * w = wbfs.wbfs;
876     if ( slot_info && path[0] == '/' )
877     {
878 	char * end;
879 	const uint slot = strtoul(path+1,&end,10);
880 	if ( end > path+1
881 	    && ( !*end || *end == '/' )
882 	    && slot < n_slots
883 	    && w->head->disc_table[slot] )
884 	{
885 	    found_slot = slot;
886 	    path = end;
887 	}
888     }
889 
890     if (subpath)
891 	*subpath = path;
892     return found_slot;
893 }
894 
895 ///////////////////////////////////////////////////////////////////////////////
896 
analyze_wbfs_id(ccp path,bool extend)897 static int analyze_wbfs_id
898 (
899     ccp			path,		// source path
900     bool		extend		// true; allow "name [id]"
901 )
902 {
903     TRACE("analyze_wbfs_id(%s)\n",path);
904     DASSERT(path);
905 
906     if (!slot_info)
907 	return -1;
908 
909     const int slen = strlen(path);
910     bool ok = path[0] == '/' && slen == 7;
911     if ( !ok
912 	&& extend
913 	&& slen >= 8
914 	&& path[slen-8] == '['
915 	&& path[slen-1] == ']' )
916     {
917 	ok = true;
918 	path += slen - 8;
919     }
920     noTRACE("ANA-ID: ok=%d, extend=%d, path=|%s|\n",ok,extend,path);
921 
922     if (ok)
923     {
924 	int slot;
925 	for ( slot = 0; slot < n_slots; slot++ )
926 	    if ( !memcmp(path+1,slot_info[slot].id6,6) )
927 		return slot;
928     }
929 
930     return -1;
931 }
932 
933 //
934 ///////////////////////////////////////////////////////////////////////////////
935 ///////////////			wfuse_getattr()			///////////////
936 ///////////////////////////////////////////////////////////////////////////////
937 
get_iso_size(DiscFile_t * df)938 static u64 get_iso_size
939 (
940     DiscFile_t		* df
941 )
942 {
943     DASSERT(df);
944 
945     u64 fsize = df->sf->file_size;
946     if (!fsize)
947 	fsize = (u64)WII_SECTOR_SIZE
948 		* ( df->disc->usage_max > WII_SECTORS_SINGLE_LAYER
949 		  ? df->disc->usage_max : WII_SECTORS_SINGLE_LAYER );
950     return fsize;
951 }
952 
953 ///////////////////////////////////////////////////////////////////////////////
954 
wfuse_getattr_iso(const char * path,struct stat * st,DiscFile_t * df)955 static int wfuse_getattr_iso
956 (
957     const char		* path,
958     struct stat		* st,
959     DiscFile_t		* df
960 )
961 {
962     TRACE("##### wfuse_getattr_iso(%s)\n",path);
963     DASSERT(path);
964     DASSERT(st);
965     DASSERT(df);
966     DASSERT(df->sf);
967 
968     char pbuf[INFO_SIZE];
969 
970     enumAnaPath ap;
971     ccp subpath = analyze_path(&ap,path,ana_path_tab_iso);
972 
973     switch(ap)
974     {
975 	case AP_ROOT:
976 	    memcpy(st,&df->stat_dir,sizeof(*st));
977 	    st->st_nlink = 3;
978 	    return 0;
979 
980 	case AP_ISO_DISC:
981 	    if ( !is_fst && !*subpath )
982 	    {
983 		memcpy(st,&df->stat_file,sizeof(*st));
984 		st->st_size = get_iso_size(df);
985 		return 0;
986 	    }
987 	    break;
988 
989 	case AP_ISO_INFO:
990 	    if (!*subpath)
991 	    {
992 		memcpy(st,&df->stat_file,sizeof(*st));
993 		st->st_size = print_iso_info(df,pbuf,sizeof(pbuf));
994 		return 0;
995 	    }
996 	    break;
997 
998 	case AP_ISO_PART:
999 	    if (!*subpath)
1000 	    {
1001 		memcpy(st,&df->stat_dir,sizeof(*st));
1002 		if (df->disc)
1003 		    st->st_nlink += df->disc->n_part;
1004 		return 0;
1005 	    }
1006 
1007 	    if ( strlen(subpath) == 5
1008 		 && *subpath == '/'
1009 		 && isalnum(subpath[1])
1010 		 && isalnum(subpath[2])
1011 		 && isalnum(subpath[3])
1012 		 && isalnum(subpath[4]) )
1013 	    {
1014 		memcpy(st,&df->stat_link,sizeof(*st));
1015 		return 0;
1016 	    }
1017 
1018 	    wd_part_t * part = analyze_part(&subpath,subpath,df->disc);
1019 	    if (part)
1020 	    {
1021 		if (!strcmp(subpath,"/info.txt"))
1022 		{
1023 		    memcpy(st,&df->stat_file,sizeof(*st));
1024 		    st->st_size = print_part_info(part,pbuf,sizeof(pbuf));
1025 		    return 0;
1026 		}
1027 
1028 		WiiFstFile_t *file, *end;
1029 		const uint slen = get_fst_pointer(0,&file,&end,df,part,subpath);
1030 		if (file)
1031 		{
1032 		    if ( file->icm == WD_ICM_DIRECTORY )
1033 		    {
1034 			memcpy(st,&df->stat_dir,sizeof(*st));
1035 			for ( file++;
1036 			      file < end && !memcmp(subpath,file->path,slen);
1037 			      file++ )
1038 			{
1039 			    if ( file->icm == WD_ICM_DIRECTORY )
1040 			    {
1041 				ccp path = file->path+slen;
1042 				if ( *path == '/' )
1043 				{
1044 				    path++;
1045 				    if ( *path && !strchr(path,'/') )
1046 					st->st_nlink++;
1047 				}
1048 			    }
1049 			}
1050 		    }
1051 		    else
1052 		    {
1053 			memcpy(st,&df->stat_file,sizeof(*st));
1054 			st->st_size = file->size;
1055 		    }
1056 		    return 0;
1057 		}
1058 	    }
1059 	    break;
1060 
1061 	case AP_ISO_PART_DATA:
1062 	case AP_ISO_PART_UPDATE:
1063 	case AP_ISO_PART_CHANNEL:
1064 	case AP_ISO_PART_MAIN:
1065 	    if (!*subpath)
1066 	    {
1067 		memcpy(st,&df->stat_link,sizeof(*st));
1068 		return 0;
1069 	    }
1070 	    break;
1071 
1072 	default:
1073 	    break;
1074     }
1075 
1076     memset(st,0,sizeof(*st));
1077     return -ENOATTR;
1078 }
1079 
1080 ///////////////////////////////////////////////////////////////////////////////
1081 
wfuse_getattr(const char * path,struct stat * st)1082 static int wfuse_getattr
1083 (
1084     const char		* path,
1085     struct stat		* st
1086 )
1087 {
1088     TRACE("##### wfuse_getattr(%s)\n",path);
1089     DASSERT(path);
1090     DASSERT(st);
1091 
1092     enumAnaPath ap;
1093     ccp subpath = analyze_path(&ap,path,ana_path_tab_root);
1094 
1095     char pbuf[INFO_SIZE];
1096 
1097     switch(ap)
1098     {
1099 	case AP_ROOT:
1100 	    memcpy(st,&stat_dir,sizeof(*st));
1101 	    st->st_nlink = is_wbfs_iso ? 4 : 3;
1102 	    return 0;
1103 
1104 	case AP_ROOT_INFO:
1105 	    if (!*subpath)
1106 	    {
1107 		memcpy(st,&stat_file,sizeof(*st));
1108 		st->st_size = print_root_info(pbuf,sizeof(pbuf));
1109 		return 0;
1110 	    }
1111 	    break;
1112 
1113 	case AP_ISO:
1114 	    noTRACE(" -> AP_ISO, sub=%s\n",subpath);
1115 	    if (!*subpath) // -> /iso
1116 	    {
1117 		switch(open_mode)
1118 		{
1119 		    case OMODE_ISO:
1120 			memcpy(st,&stat_dir,sizeof(*st));
1121 			st->st_nlink = 3;
1122 			return 0;
1123 
1124 		    case OMODE_WBFS_ISO:
1125 			memcpy(st,&stat_link,sizeof(*st));
1126 			return 0;
1127 
1128 		    case OMODE_WBFS:
1129 			memset(st,0,sizeof(*st));
1130 			return 1;
1131 		}
1132 	    }
1133 	    return wfuse_getattr_iso(subpath,st,dfile);
1134 
1135 	case AP_WBFS:
1136 	    if ( is_wbfs && !*subpath )
1137 	    {
1138 		memcpy(st,&stat_dir,sizeof(*st));
1139 		st->st_nlink = 5;
1140 		return 0;
1141 	    }
1142 	    break;
1143 
1144 	case AP_WBFS_SLOT:
1145 	    if (!is_wbfs)
1146 		break;
1147 	    TRACE("subpath = |%s|\n",subpath);
1148 	    if (!*subpath)
1149 	    {
1150 		memcpy(st,&stat_dir,sizeof(*st));
1151 		st->st_nlink = 2 + wbfs.used_discs;
1152 		return 0;
1153 	    }
1154 
1155 	    const int slot = analyze_slot(&subpath,subpath);
1156 	    if ( slot >= 0 )
1157 	    {
1158 		if (!*subpath)
1159 		{
1160 		    memcpy(st,&stat_dir,sizeof(*st));
1161 		    st->st_nlink = 3;
1162 		    DASSERT(slot_info);
1163 		    SlotInfo_t * si = slot_info + slot;
1164 		    st->st_atime = si->atime;
1165 		    st->st_mtime = si->mtime;
1166 		    st->st_ctime = si->ctime;
1167 		    return 0;
1168 		}
1169 
1170 		DiscFile_t * df = get_disc_file(slot);
1171 		if (df)
1172 		{
1173 		    const int stat = wfuse_getattr_iso(subpath,st,df);
1174 		    free_disc_file(df);
1175 		    return stat;
1176 		}
1177 	    }
1178 	    break;
1179 
1180 	case AP_WBFS_ID:
1181 	case AP_WBFS_TITLE:
1182 	    if (!is_wbfs)
1183 		break;
1184 	    if (!*subpath)
1185 	    {
1186 		memcpy(st,&stat_dir,sizeof(*st));
1187 		return 0;
1188 	    }
1189 	    else
1190 	    {
1191 		int slot = analyze_wbfs_id(subpath,ap==AP_WBFS_TITLE);
1192 		if ( slot >= 0 )
1193 		{
1194 		    memcpy(st,&stat_link,sizeof(*st));
1195 		    SlotInfo_t * si = slot_info + slot;
1196 		    st->st_atime = si->atime;
1197 		    st->st_mtime = si->mtime;
1198 		    st->st_ctime = si->ctime;
1199 		    return 0;
1200 		}
1201 	    }
1202 	    break;
1203 
1204 	case AP_WBFS_INFO:
1205 	    if (!*subpath)
1206 	    {
1207 		memcpy(st,&stat_file,sizeof(*st));
1208 		st->st_size = print_wbfs_info(pbuf,sizeof(pbuf));
1209 		return 0;
1210 	    }
1211 	    break;
1212 
1213 	default:
1214 	    break;
1215     }
1216 
1217     memset(st,0,sizeof(*st));
1218     return -ENOATTR;
1219 }
1220 
1221 //
1222 ///////////////////////////////////////////////////////////////////////////////
1223 ///////////////			wfuse_read()			///////////////
1224 ///////////////////////////////////////////////////////////////////////////////
1225 
copy_helper(char * buf,size_t size,off_t offset,const void * src,size_t src_len)1226 static int copy_helper
1227 (
1228     char		* buf,		// read buffer
1229     size_t		size,		// size of buf and size to read
1230     off_t		offset,		// read offset
1231     const void		* src,		// source buffer
1232     size_t		src_len		// length of 'copy_buf'
1233 )
1234 {
1235     DASSERT(buf);
1236     DASSERT(src);
1237 
1238     if ( offset >= src_len )
1239 	return 0;
1240 
1241     src_len -= offset;
1242     if ( src_len > size )
1243 	 src_len = size;
1244     memcpy(buf,(ccp)src+offset,src_len);
1245     return src_len;
1246 }
1247 
1248 ///////////////////////////////////////////////////////////////////////////////
1249 
wfuse_read_iso(const char * path,char * buf,size_t size,off_t offset,fuse_file_info * info,DiscFile_t * df,char * pbuf,size_t pbuf_size)1250 static int wfuse_read_iso
1251 (
1252     const char		* path,		// path to the file
1253     char		* buf,		// read buffer
1254     size_t		size,		// size of buf and size to read
1255     off_t		offset,		// read offset
1256     fuse_file_info	* info,		// fuse info
1257 
1258     DiscFile_t		* df,		// related disc file
1259     char		* pbuf,		// temporary print buffer
1260     size_t		pbuf_size	// size of 'pbuf'
1261 )
1262 {
1263     TRACE("##### wfuse_read_iso(%s,%llu+%zu)\n",path,(u64)offset,size);
1264 
1265     enumAnaPath ap;
1266     ccp subpath = analyze_path(&ap,path,ana_path_tab_iso);
1267     wd_part_t * part;
1268 
1269     switch(ap)
1270     {
1271 	case AP_ISO_INFO:
1272 	    if (!*subpath)
1273 		return copy_helper(buf,size,offset,pbuf,
1274 					print_iso_info(df,pbuf,pbuf_size));
1275 	    break;
1276 
1277 	case AP_ISO_DISC:
1278 	    if ( !is_fst && !*subpath )
1279 	    {
1280 		const u64 fsize = get_iso_size(df);
1281 		if ( offset < fsize )
1282 		{
1283 		    if ( size > fsize - offset )
1284 			 size = fsize - offset;
1285 		    return ReadSF(df->sf,offset,buf,size) ? -EIO : size;
1286 		}
1287 	    }
1288 	    return 0;
1289 
1290 	case AP_ISO_PART:
1291 	    part = analyze_part(&subpath,subpath,df->disc);
1292 	    if ( part && *subpath )
1293 	    {
1294 		if (!strcmp(subpath,"/info.txt"))
1295 		    return copy_helper(buf,size,offset,pbuf,
1296 					print_part_info(part,pbuf,pbuf_size));
1297 
1298 		WiiFstPart_t *fst_part;
1299 		WiiFstFile_t *file;
1300 		get_fst_pointer(&fst_part,&file,0,df,part,subpath);
1301 		if ( file && file->icm != WD_ICM_DIRECTORY )
1302 		{
1303 		    if ( offset < file->size )
1304 		    {
1305 			if ( size > file->size - offset )
1306 			     size = file->size - offset;
1307 			lock_mutex();
1308 			int stat = ReadFileFST(fst_part,file,offset,buf,size) ? -EIO : size;
1309 			unlock_mutex();
1310 			return stat;
1311 		    }
1312 		    return 0;
1313 		}
1314 	    }
1315 	    break;
1316 
1317 	default:
1318 	    break;
1319     }
1320 
1321     return -ENOENT;
1322 }
1323 
1324 ///////////////////////////////////////////////////////////////////////////////
1325 
wfuse_read(const char * path,char * buf,size_t size,off_t offset,fuse_file_info * info)1326 static int wfuse_read
1327 (
1328     const char		* path,		// path to the file
1329     char		* buf,		// read buffer
1330     size_t		size,		// size of buf and size to read
1331     off_t		offset,		// read offset
1332     fuse_file_info	* info		// fuse info
1333 )
1334 {
1335     TRACE("##### wfuse_read(%s,%llu+%zu)\n",path,(u64)offset,size);
1336 
1337     enumAnaPath ap;
1338     ccp subpath = analyze_path(&ap,path,ana_path_tab_root);
1339 
1340     char pbuf[INFO_SIZE];
1341 
1342     switch(ap)
1343     {
1344 	case AP_ROOT_INFO:
1345 	    if (!*subpath)
1346 		return copy_helper(buf,size,offset,pbuf,
1347 					print_root_info(pbuf,sizeof(pbuf)));
1348 	    break;
1349 
1350 	case AP_ISO:
1351 	    return wfuse_read_iso( subpath, buf, size, offset, info,
1352 					dfile, pbuf,sizeof(pbuf) );
1353 
1354 	case AP_WBFS_SLOT:
1355 	    if ( is_wbfs && *subpath )
1356 	    {
1357 		const int slot = analyze_slot(&subpath,subpath);
1358 		if ( slot >= 0 )
1359 		{
1360 		    DiscFile_t * df = get_disc_file(slot);
1361 		    if (df)
1362 		    {
1363 			const int stat
1364 			    = wfuse_read_iso( subpath, buf, size, offset, info,
1365 					df, pbuf,sizeof(pbuf) );
1366 			free_disc_file(df);
1367 			return stat;
1368 		    }
1369 		}
1370 	    }
1371 	    break;
1372 
1373 	case AP_WBFS_INFO:
1374 	    if (!*subpath)
1375 		return copy_helper(buf,size,offset,pbuf,
1376 					print_wbfs_info(pbuf,sizeof(pbuf)));
1377 	    break;
1378 
1379 	default:
1380 	    break;
1381     }
1382 
1383     return -ENOENT;
1384 }
1385 
1386 //
1387 ///////////////////////////////////////////////////////////////////////////////
1388 ///////////////			wfuse_readlink()		///////////////
1389 ///////////////////////////////////////////////////////////////////////////////
1390 
wfuse_readlink_iso(const char * path,char * fuse_buf,size_t bufsize,DiscFile_t * df)1391 static int wfuse_readlink_iso
1392 (
1393     const char		* path,
1394     char		* fuse_buf,
1395     size_t		bufsize,
1396     DiscFile_t		* df
1397 )
1398 {
1399     TRACE("##### wfuse_readlink(%s)\n",path);
1400     DASSERT(fuse_buf);
1401     DASSERT(df);
1402 
1403     enumAnaPath ap;
1404     ccp subpath = analyze_path(&ap,path,ana_path_tab_iso);
1405 
1406     switch(ap)
1407     {
1408 	case AP_ROOT:
1409 	    if ( !*subpath && is_wbfs_iso )
1410 	    {
1411 		snprintf(fuse_buf,bufsize,"wbfs/slot/%u/",wbfs_slot);
1412 		return 0;
1413 	    }
1414 	    break;
1415 
1416 	case AP_ISO_PART_DATA:
1417 	    if (!*subpath)
1418 	    {
1419 		wd_disc_t * disc = df->disc;
1420 		if ( disc && disc->data_part )
1421 		    snprintf(fuse_buf,bufsize,"%u.%u/",
1422 			disc->data_part->ptab_index,
1423 			disc->data_part->ptab_part_index);
1424 		return 0;
1425 	    }
1426 	    break;
1427 
1428 	case AP_ISO_PART_UPDATE:
1429 	    if (!*subpath)
1430 	    {
1431 		wd_disc_t * disc = df->disc;
1432 		if ( disc && disc->update_part )
1433 		    snprintf(fuse_buf,bufsize,"%u.%u/",
1434 			disc->update_part->ptab_index,
1435 			disc->update_part->ptab_part_index);
1436 		return 0;
1437 	    }
1438 	    break;
1439 
1440 	case AP_ISO_PART_CHANNEL:
1441 	    if (!*subpath)
1442 	    {
1443 		wd_disc_t * disc = df->disc;
1444 		if ( disc && disc->channel_part )
1445 		    snprintf(fuse_buf,bufsize,"%u.%u/",
1446 			disc->channel_part->ptab_index,
1447 			disc->channel_part->ptab_part_index);
1448 		return 0;
1449 	    }
1450 	    break;
1451 
1452 	case AP_ISO_PART_MAIN:
1453 	    if (!*subpath)
1454 	    {
1455 		wd_disc_t * disc = df->disc;
1456 		if ( disc && disc->main_part )
1457 		    snprintf(fuse_buf,bufsize,"%u.%u/",
1458 			disc->main_part->ptab_index,
1459 			disc->main_part->ptab_part_index);
1460 		return 0;
1461 	    }
1462 	    break;
1463 
1464 	case AP_ISO_PART:
1465 	    if ( strlen(subpath) == 5
1466 		 && *subpath == '/'
1467 		 && isalnum(subpath[1])
1468 		 && isalnum(subpath[2])
1469 		 && isalnum(subpath[3])
1470 		 && isalnum(subpath[4]) )
1471 	    {
1472 		wd_disc_t * disc = df->disc;
1473 		if (disc)
1474 		{
1475 		    u32 ptype = (( subpath[1] << 8 | subpath[2] ) << 8
1476 					| subpath[3] ) << 8 | subpath[4];
1477 		    int ip;
1478 		    for ( ip = 0; ip < disc->n_part; ip++ )
1479 		    {
1480 			wd_part_t * part = disc->part + ip;
1481 			if ( part->part_type == ptype )
1482 			{
1483 			    snprintf(fuse_buf,bufsize,"%u.%u/",
1484 				part->ptab_index, part->ptab_part_index);
1485 			    return 0;
1486 			}
1487 		    }
1488 		}
1489 		snprintf(fuse_buf,bufsize,"main");
1490 		return 0;
1491 	    }
1492 
1493 	default:
1494 	    break;
1495     }
1496     *fuse_buf = 0;
1497     return 1;
1498 }
1499 
1500 ///////////////////////////////////////////////////////////////////////////////
1501 
wfuse_readlink(const char * path,char * fuse_buf,size_t bufsize)1502 static int wfuse_readlink
1503 (
1504     const char		* path,
1505     char		* fuse_buf,
1506     size_t		bufsize
1507 )
1508 {
1509     TRACE("##### wfuse_readlink(%s)\n",path);
1510     DASSERT(fuse_buf);
1511 
1512     enumAnaPath ap;
1513     ccp subpath = analyze_path(&ap,path,ana_path_tab_root);
1514 
1515     switch(ap)
1516     {
1517 	case AP_ISO:
1518 	    return wfuse_readlink_iso(subpath,fuse_buf,bufsize,dfile);
1519 
1520 	case AP_WBFS_ID:
1521 	case AP_WBFS_TITLE:
1522 	    if ( is_wbfs && *subpath )
1523 	    {
1524 		int slot = analyze_wbfs_id(subpath,ap==AP_WBFS_TITLE);
1525 		if ( slot >= 0 )
1526 		    snprintf(fuse_buf,bufsize,"../slot/%u/",slot);
1527 		return 0;
1528 	    }
1529 	    break;
1530 
1531 	case AP_WBFS_SLOT:
1532 	    if (!is_wbfs)
1533 		break;
1534 	    if (*subpath)
1535 	    {
1536 		const int slot = analyze_slot(&subpath,subpath);
1537 		if ( slot >= 0 )
1538 		{
1539 		    DiscFile_t * df = get_disc_file(slot);
1540 		    if (df)
1541 		    {
1542 			const int stat
1543 			    = wfuse_readlink_iso(subpath,fuse_buf,bufsize,df);
1544 			free_disc_file(df);
1545 			return stat;
1546 		    }
1547 		}
1548 	    }
1549 	    break;
1550 
1551 	default:
1552 	    break;
1553     }
1554     *fuse_buf = 0;
1555     return 1;
1556 }
1557 
1558 //
1559 ///////////////////////////////////////////////////////////////////////////////
1560 ///////////////			wfuse_readdir()			///////////////
1561 ///////////////////////////////////////////////////////////////////////////////
1562 
wfuse_readdir_iso(const char * path,void * fuse_buf,fuse_fill_dir_t filler,off_t offset,fuse_file_info * info,DiscFile_t * df)1563 static int wfuse_readdir_iso
1564 (
1565     const char		* path,
1566     void		* fuse_buf,
1567     fuse_fill_dir_t	filler,
1568     off_t		offset,
1569     fuse_file_info	* info,
1570     DiscFile_t		* df
1571 )
1572 {
1573     TRACE("##### wfuse_readdir_iso(%s,df=%zu)\n",path,df-dfile);
1574     DASSERT(filler);
1575     DASSERT(df);
1576     DASSERT(df->sf);
1577 
1578     enumAnaPath ap;
1579     ccp subpath = analyze_path(&ap,path,ana_path_tab_iso);
1580 
1581     char pbuf[100];
1582 
1583     switch(ap)
1584     {
1585 	case AP_ROOT:
1586 	    if (!*subpath)
1587 	    {
1588 		filler(fuse_buf,".",0,0);
1589 		filler(fuse_buf,"..",0,0);
1590 		filler(fuse_buf,"part",0,0);
1591 		filler(fuse_buf,"info.txt",0,0);
1592 		if (!is_fst)
1593 		    filler(fuse_buf,"disc.iso",0,0);
1594 	    }
1595 	    break;
1596 
1597 	case AP_ISO_PART:
1598 	    filler(fuse_buf,".",0,0);
1599 	    filler(fuse_buf,"..",0,0);
1600 
1601 	    if (!*subpath)
1602 	    {
1603 		wd_disc_t * disc = df->disc;
1604 		if (disc)
1605 		{
1606 		    int ip;
1607 		    for ( ip = 0; ip < disc->n_part; ip++ )
1608 		    {
1609 			wd_part_t * part = disc->part + ip;
1610 			snprintf( pbuf, sizeof(pbuf),"%u.%u",
1611 				part->ptab_index, part->ptab_part_index );
1612 			filler(fuse_buf,pbuf,0,0);
1613 
1614 			u32 ptype = htonl(disc->part[ip].part_type);
1615 			ccp id4 = (ccp)&ptype;
1616 			if ( isalnum(id4[0]) && isalnum(id4[1])
1617 				&& isalnum(id4[2]) && isalnum(id4[3]) )
1618 			{
1619 			    memcpy(pbuf,id4,4);
1620 			    pbuf[4] = 0;
1621 			    filler(fuse_buf,pbuf,0,0);
1622 			}
1623 		    }
1624 		    if (disc->data_part)
1625 			filler(fuse_buf,"data",0,0);
1626 		    if (disc->update_part)
1627 			filler(fuse_buf,"update",0,0);
1628 		    if (disc->channel_part)
1629 			filler(fuse_buf,"channel",0,0);
1630 		    if (disc->main_part)
1631 			filler(fuse_buf,"main",0,0);
1632 		}
1633 		return 0;
1634 	    }
1635 
1636 	    wd_part_t * part = analyze_part(&subpath,subpath,df->disc);
1637 	    if (part)
1638 	    {
1639 		if (!*subpath)
1640 		    filler(fuse_buf,"info.txt",0,0);
1641 
1642 		WiiFstFile_t *ptr, *end;
1643 		int slen = get_fst_pointer(0,&ptr,&end,df,part,subpath);
1644 		if ( slen >= 0 )
1645 		{
1646 		    for ( ; ptr < end && !memcmp(subpath,ptr->path,slen); ptr++ )
1647 		    {
1648 			ccp path = ptr->path+slen;
1649 			noTRACE("XCHECK: %s\n",path);
1650 			if ( *path == '/' )
1651 			{
1652 			    path++;
1653 			    TRACE("PATH: %s\n",path);
1654 			    if ( *path && !strchr(path,'/') )
1655 				filler(fuse_buf,path,0,0);
1656 			}
1657 		    }
1658 		}
1659 	    }
1660 	    break;
1661 
1662 	default:
1663 	    break;
1664 
1665     }
1666     return 0;
1667 }
1668 
1669 ///////////////////////////////////////////////////////////////////////////////
1670 
wfuse_readdir(const char * path,void * fuse_buf,fuse_fill_dir_t filler,off_t offset,fuse_file_info * info)1671 static int wfuse_readdir
1672 (
1673     const char		* path,
1674     void		* fuse_buf,
1675     fuse_fill_dir_t	filler,
1676     off_t		offset,
1677     fuse_file_info	* info
1678 )
1679 {
1680     TRACE("##### wfuse_readdir(%s)\n",path);
1681 
1682     DASSERT(filler);
1683     enumAnaPath ap;
1684     ccp subpath = analyze_path(&ap,path,ana_path_tab_root);
1685 
1686     char pbuf[100];
1687 
1688     switch(ap)
1689     {
1690 	case AP_ROOT:
1691 	    if (!*subpath)
1692 	    {
1693 		filler(fuse_buf,".",0,0);
1694 		filler(fuse_buf,"..",0,0);
1695 		if (is_iso)
1696 		    filler(fuse_buf,"iso",0,0);
1697 		if (is_wbfs)
1698 		    filler(fuse_buf,"wbfs",0,0);
1699 		filler(fuse_buf,"info.txt",0,0);
1700 	    }
1701 	    break;
1702 
1703 	case AP_ISO:
1704 	    return wfuse_readdir_iso(subpath,fuse_buf,filler,offset,info,dfile);
1705 
1706 	case AP_WBFS:
1707 	    if ( is_wbfs && !*subpath )
1708 	    {
1709 		filler(fuse_buf,".",0,0);
1710 		filler(fuse_buf,"..",0,0);
1711 		filler(fuse_buf,"slot",0,0);
1712 		filler(fuse_buf,"id",0,0);
1713 		filler(fuse_buf,"title",0,0);
1714 		filler(fuse_buf,"info.txt",0,0);
1715 	    }
1716 	    break;
1717 
1718 	case AP_WBFS_SLOT:
1719 	    if (!is_wbfs)
1720 		break;
1721 
1722 	    if (!*subpath)
1723 	    {
1724 		filler(fuse_buf,".",0,0);
1725 		filler(fuse_buf,"..",0,0);
1726 		wbfs_t * w = wbfs.wbfs;
1727 		if (w)
1728 		{
1729 		    int slot;
1730 		    for ( slot = 0; slot < w->max_disc; slot++ )
1731 			if (w->head->disc_table[slot])
1732 			{
1733 			    snprintf(pbuf,sizeof(pbuf),"%u",slot);
1734 			    filler(fuse_buf,pbuf,0,0);
1735 			}
1736 		}
1737 	    }
1738 	    else
1739 	    {
1740 		const int slot = analyze_slot(&subpath,subpath);
1741 		if ( slot >= 0 )
1742 		{
1743 		    DiscFile_t * df = get_disc_file(slot);
1744 		    if (df)
1745 		    {
1746 			const int stat
1747 			    = wfuse_readdir_iso(subpath,fuse_buf,filler,offset,info,df);
1748 			free_disc_file(df);
1749 			return stat;
1750 		    }
1751 		}
1752 	    }
1753 	    break;
1754 
1755 	case AP_WBFS_ID:
1756 	case AP_WBFS_TITLE:
1757 	    if ( is_wbfs && slot_info && !*subpath )
1758 	    {
1759 		filler(fuse_buf,".",0,0);
1760 		filler(fuse_buf,"..",0,0);
1761 		int slot;
1762 		for ( slot = 0; slot < n_slots; slot++ )
1763 		{
1764 		    SlotInfo_t * si = slot_info + slot;
1765 		    if (si->id6[0])
1766 		    {
1767 			if ( ap == AP_WBFS_TITLE )
1768 			{
1769 			    snprintf(pbuf,sizeof(pbuf),
1770 					"%.80s [%s]", si->fname, si->id6 );
1771 			    filler(fuse_buf,pbuf,0,0);
1772 			}
1773 			else
1774 			    filler(fuse_buf,si->id6,0,0);
1775 		    }
1776 		}
1777 	    }
1778 	    break;
1779 
1780 	default:
1781 	    break;
1782     }
1783     return 0;
1784 }
1785 
1786 //
1787 ///////////////////////////////////////////////////////////////////////////////
1788 ///////////////			wfuse_destroy()			///////////////
1789 ///////////////////////////////////////////////////////////////////////////////
1790 
sleep_msec(long msec)1791 static int sleep_msec ( long msec )
1792 {
1793     struct timespec ts;
1794     ts.tv_sec  = msec/1000;
1795     ts.tv_nsec = ( msec % 1000 ) * 1000000;
1796     return nanosleep(&ts,0);
1797 }
1798 
1799 ///////////////////////////////////////////////////////////////////////////////
1800 
wfuse_destroy()1801 void wfuse_destroy()
1802 {
1803     TRACE("DESTROY\n");
1804     if (opt_create)
1805     {
1806 	TRACE("TRY UMOUNT #1: %s\n",mount_point);
1807 	if ( rmdir(mount_point) == -1 )
1808 	{
1809 	    // give it a second chance
1810 	    sleep_msec(1000);
1811 	    TRACE("TRY UMOUNT #2: %s\n",mount_point);
1812 	    rmdir(mount_point);
1813 	}
1814     }
1815 }
1816 
1817 //
1818 ///////////////////////////////////////////////////////////////////////////////
1819 ///////////////			    umount()			///////////////
1820 ///////////////////////////////////////////////////////////////////////////////
1821 
exec_cmd(ccp cmd,ccp p1,ccp p2,ccp p3,bool silent)1822 static int exec_cmd ( ccp cmd, ccp p1, ccp p2, ccp p3, bool silent )
1823 {
1824     const pid_t pid = fork();
1825     if ( pid == -1 )
1826 	return ERROR1(ERR_FATAL,"Can't exec fork()\n");
1827 
1828     if (!pid)
1829     {
1830 	// *** child ***
1831 
1832 	char * argv[5], **arg = argv;
1833 	*arg++ = (char*)cmd;
1834 	if (p1) *arg++ = (char*)p1;
1835 	if (p2) *arg++ = (char*)p2;
1836 	if (p3) *arg++ = (char*)p3;
1837 	DASSERT( arg-argv < sizeof(argv)/sizeof(*argv) );
1838 	*arg = 0;
1839 
1840 	if (silent)
1841 	{
1842 	    int fd = creat("/dev/null",0777);
1843 	    if ( fd == -1 )
1844 		perror(0);
1845 	    else
1846 	    {
1847 		dup2(fd,STDOUT_FILENO);
1848 		dup2(fd,STDERR_FILENO);
1849 	    }
1850 	}
1851 
1852 	execvp(cmd,argv);
1853 	PRINT("CALL to '%s' failed\n",cmd);
1854 	exit(127);
1855     }
1856 
1857     // *** parent ***
1858 
1859     int status;
1860     const pid_t wpid = waitpid(pid,&status,0);
1861     if ( wpid == -1 )
1862 	return ERROR1(ERR_FATAL,"Can't exec waitpid()\n");
1863 
1864     const int exit_stat = WEXITSTATUS(status);
1865     noPRINT("CALLED[%d,%d]: %s\n",status,exit_stat,cmd);
1866     return WIFEXITED(status) && exit_stat != 127 ? exit_stat : -1;
1867 }
1868 
1869 ///////////////////////////////////////////////////////////////////////////////
1870 
umount_path(ccp mpt,bool silent)1871 static enumError umount_path ( ccp mpt, bool silent )
1872 {
1873     if (!IsDirectory(mpt,0))
1874     {
1875 	if (!silent)
1876 	    ERROR0(ERR_WARNING,"Not a directory: %s\n",mpt);
1877 	return ERR_WARNING;
1878     }
1879 
1880     if ( !silent && verbose >= 0 )
1881 	printf(WFUSE_SHORT " umount %s\n",mpt);
1882 
1883     static bool use_fusermount = true;
1884     if (use_fusermount)
1885     {
1886 	const int stat = exec_cmd("fusermount", "-u", opt_lazy ? "-z" : 0, mpt, silent );
1887 	if ( stat == -1 )
1888 	{
1889 	    use_fusermount = false;
1890 	    if ( !silent && verbose >= 0 )
1891 		ERROR0(ERR_WARNING,"'fusermount' not found, try 'umount' now!\n");
1892 	}
1893 	else
1894 	    return stat ? ERR_WARNING : ERR_OK;
1895     }
1896 
1897     const int stat = exec_cmd("umount", opt_lazy ? "-l" : 0, mpt, 0, silent );
1898     if ( stat == -1 )
1899 	return ERROR0(ERR_FATAL,
1900 		"Can't find neither 'fusermount' nor 'umount' -> abort\n");
1901 
1902     return stat ? ERR_WARNING : ERR_OK;
1903 }
1904 
1905 ///////////////////////////////////////////////////////////////////////////////
1906 
umount(int argc,char ** argv)1907 static enumError umount ( int argc, char ** argv )
1908 {
1909     if ( optind == argc )
1910 	hint_exit(ERR_SYNTAX);
1911 
1912     const bool silent = verbose < -1;
1913     int argi, errcount = 0;
1914 
1915     for ( argi = optind; argi < argc; argi++ )
1916 	if (umount_path(argv[argi],silent))
1917 	    errcount++;
1918     return errcount ? ERR_WARNING : ERR_OK;
1919 }
1920 
1921 //
1922 ///////////////////////////////////////////////////////////////////////////////
1923 ///////////////			    main()			///////////////
1924 ///////////////////////////////////////////////////////////////////////////////
1925 
main(int argc,char ** argv)1926 int main ( int argc, char ** argv )
1927 {
1928     //----- setup
1929 
1930     SetupLib(argc,argv,WFUSE_SHORT,PROG_WFUSE);
1931     InitializeSF(&main_sf);
1932     InitializeWBFS(&wbfs);
1933     memset(&dfile,0,sizeof(dfile));
1934     GetTitle("ABC",0); // force loading title DB
1935 
1936     add_arg( argv[0] ? argv[0] : WFUSE_SHORT, 0 );
1937 
1938 
1939     //----- process arguments
1940 
1941     if ( argc < 2 )
1942     {
1943 	printf("\n%s\n%s\nVisit %s%s for more info.\n\n",
1944 		text_logo, TITLE, URI_HOME, WFUSE_SHORT );
1945 	hint_exit(ERR_OK);
1946     }
1947 
1948     if (CheckOptions(argc,argv))
1949 	hint_exit(ERR_SYNTAX);
1950 
1951     if ( verbose >= 0 )
1952 	printf( TITLE "\n" );
1953 
1954     if (opt_umount)
1955 	return umount(argc,argv);
1956 
1957     if ( optind + 2 != argc )
1958 	hint_exit(ERR_SYNTAX);
1959 
1960     source_file = argv[optind];
1961     mount_point = argv[optind+1];
1962 
1963 
1964     //----- open file
1965 
1966     main_sf.allow_fst = true;
1967     enumError err = OpenSF(&main_sf,source_file,true,false);
1968     if (err)
1969 	return err;
1970 
1971 
1972     //----- setup stat templates
1973 
1974     memcpy(&stat_dir, &main_sf.f.st,sizeof(stat_dir));
1975     memcpy(&stat_file,&main_sf.f.st,sizeof(stat_file));
1976     memcpy(&stat_link,&main_sf.f.st,sizeof(stat_link));
1977 
1978     const mode_t mode	= main_sf.f.st.st_mode & 0444;
1979     stat_dir .st_mode	= S_IFDIR | mode | mode >> 2;
1980     stat_file.st_mode	= S_IFREG | mode;
1981     stat_link.st_mode	= S_IFLNK | mode | mode >> 2;
1982 
1983     stat_dir .st_nlink	= 2;
1984     stat_file.st_nlink	= 1;
1985     stat_link.st_nlink	= 1;
1986 
1987     stat_dir .st_size	= 0;
1988     stat_file.st_size	= 0;
1989     stat_link.st_size	= 0;
1990 
1991     stat_dir .st_blocks	= 0;
1992     stat_file.st_blocks	= 0;
1993     stat_link.st_blocks	= 0;
1994 
1995 
1996     //----- analyze file type
1997 
1998     char buf[200];
1999 
2000     enumFileType ftype = AnalyzeFT(&main_sf.f);
2001     if ( ftype & FT_ID_WBFS )
2002     {
2003 	PRINT("-> WBFS\n");
2004 	is_wbfs = true;
2005 	open_mode = OMODE_WBFS;
2006 	err = SetupWBFS(&wbfs,&main_sf,true,0,0);
2007 	if (err)
2008 	    return err;
2009 	wbfs.cache_candidate = false;
2010 	CalcWBFSUsage(&wbfs);
2011 
2012 	wbfs_t * w = wbfs.wbfs;
2013 	if (!w)
2014 	    return ERR_WBFS_INVALID;
2015 
2016 	id6_t * id_list = wbfs_load_id_list(w,false);
2017 	if (!id_list)
2018 	    return ERR_WBFS_INVALID;
2019 
2020 	if ( wbfs.used_discs == 1 )
2021 	{
2022 	    wbfs_t * w = wbfs.wbfs;
2023 	    wbfs_load_id_list(w,false);
2024 	    int slot;
2025 	    for ( slot = 0; slot < w->max_disc; slot++ )
2026 		if (w->head->disc_table[slot])
2027 		{
2028 		    wbfs_slot = slot;
2029 		    is_iso = is_wbfs_iso = true;
2030 		    open_mode = OMODE_WBFS_ISO;
2031 		    break;
2032 		}
2033 	}
2034 
2035 	n_slots = w->max_disc;
2036 	slot_info = CALLOC(sizeof(*slot_info),n_slots);
2037 	int slot;
2038 	for ( slot = 0; slot < n_slots; slot++ )
2039 	{
2040 	    wbfs_disc_t * d = wbfs_open_disc_by_slot(w,slot,false);
2041 	    if (d)
2042 	    {
2043 		SlotInfo_t * si = slot_info + slot;
2044 		memcpy(si->id6,id_list[slot],6);
2045 		ccp title = GetTitle(si->id6,(ccp)d->header->dhead+WII_TITLE_OFF);
2046 		NormalizeFileName(buf,buf+sizeof(buf)-1,title,false)[0] = 0;
2047 		si->fname = STRDUP(buf);
2048 
2049 		si->atime = main_sf.f.st.st_atime;
2050 		si->mtime = main_sf.f.st.st_mtime;
2051 		si->ctime = main_sf.f.st.st_ctime;
2052 		wbfs_inode_info_t * ii = wbfs_get_disc_inode_info(d,1);
2053 		if (ii)
2054 		{
2055 		    time_t tim = ntoh64(ii->atime);
2056 		    if (tim)
2057 			si->atime = tim;
2058 		    tim = ntoh64(ii->mtime);
2059 		    if (tim)
2060 			si->mtime = tim;
2061 		    tim = ntoh64(ii->ctime);
2062 		    if (tim)
2063 			si->ctime = tim;
2064 		}
2065 		PRINT("%11llx %11llx %11llx\n",
2066 			(u64)si->atime, (u64)si->mtime, (u64)si->ctime );
2067 
2068 		d->is_dirty = false;
2069 		wbfs_close_disc(d);
2070 	    }
2071 	}
2072     }
2073     else if ( ftype & FT_A_ISO )
2074     {
2075 	PRINT("-> ISO\n");
2076 	is_iso = true;
2077 	open_mode = OMODE_ISO;
2078 
2079 	if ( ftype & FT_ID_FST )
2080 	    is_fst = true;
2081 
2082 	wd_disc_t * disc = OpenDiscSF(&main_sf,true,true);
2083 	if (!disc)
2084 	    return ERR_INVALID_FILE;
2085 
2086 	wd_calc_disc_status(disc,true);
2087 
2088 	// setup the only disc file!
2089 	dfile->used		= true;
2090 	dfile->lock_count	= 1;
2091 	dfile->slot		= -1;
2092 	dfile->sf		= &main_sf;
2093 	dfile->disc		= disc;
2094 
2095 	memcpy(&dfile->stat_dir, &stat_dir, sizeof(dfile->stat_dir ));
2096 	memcpy(&dfile->stat_file,&stat_file,sizeof(dfile->stat_file));
2097 	memcpy(&dfile->stat_link,&stat_link,sizeof(dfile->stat_link));
2098 
2099 	n_dfile			= 1;
2100     }
2101     else
2102     {
2103 	return ERROR0(ERR_INVALID_FILE,
2104 			"File type '%s' not supported: %s\n",
2105 			GetNameFT(ftype,0), source_file );
2106     }
2107 
2108     if ( verbose >= 0 )
2109 	printf("mount %s:%s -> %s\n",
2110 		oft_info[main_sf.iod.oft].name, source_file, mount_point );
2111 
2112 
2113     //----- create absolute pathes for further usage
2114 
2115     source_file = AllocRealPath(source_file);
2116     mount_point = AllocRealPath(mount_point);
2117 
2118 
2119     //----- umount first
2120 
2121     if (opt_remount)
2122     {
2123 	opt_lazy = true;
2124 	if (!umount_path(mount_point,true))
2125 	    sleep_msec(200);
2126     }
2127 
2128 
2129     //----- create mount point
2130 
2131     if (opt_create)
2132     {
2133 	struct stat st;
2134 	if ( stat(mount_point,&st) == -1 )
2135 	    mkdir(mount_point,0777);
2136 	else
2137 	    opt_create = false;
2138     }
2139 
2140 
2141     //----- start fuse
2142 
2143     static struct fuse_operations wfuse_oper =
2144     {
2145 	.getattr    = wfuse_getattr,
2146 	.read	    = wfuse_read,
2147 	.readlink   = wfuse_readlink,
2148 	.readdir    = wfuse_readdir,
2149 	.destroy    = wfuse_destroy,
2150     };
2151 
2152     add_arg(mount_point,0);
2153     TRACE("CALL fuse_main(argc=%d\n",argc);
2154     return fuse_main(wbfuse_argc,wbfuse_argv,&wfuse_oper);
2155 }
2156 
2157 //
2158 ///////////////////////////////////////////////////////////////////////////////
2159 ///////////////                     END                         ///////////////
2160 ///////////////////////////////////////////////////////////////////////////////
2161 
2162