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 Kwiirk *
20 * Copyright (c) 2009-2013 by Dirk Clemens <wiimm@wiimm.de> *
21 * *
22 ***************************************************************************
23 * *
24 * This program is free software; you can redistribute it and/or modify *
25 * it under the terms of the GNU General Public License as published by *
26 * the Free Software Foundation; either version 2 of the License, or *
27 * (at your option) any later version. *
28 * *
29 * This program is distributed in the hope that it will be useful, *
30 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
32 * GNU General Public License for more details. *
33 * *
34 * See file gpl-2.0.txt or http://www.gnu.org/licenses/gpl-2.0.txt *
35 * *
36 ***************************************************************************/
37
38 #include "libwbfs.h"
39 #include <errno.h>
40
41 ///////////////////////////////////////////////////////////////////////////////
42
43 #define WBFS_ERROR(x) do {wbfs_error(x);goto error;}while(0)
44 #define ALIGN_LBA(x) (((x)+p->hd_sec_sz-1)&(~(p->hd_sec_sz-1)))
45
46 ///////////////////////////////////////////////////////////////////////////////
47 // debugging macros
48
49 #ifndef TRACE
50 #define TRACE(...)
51 #endif
52
53 #ifndef PRINT
54 #define PRINT(...)
55 #endif
56
57 #ifndef ASSERT
58 #define ASSERT(cond)
59 #endif
60
61 ///////////////////////////////////////////////////////////////////////////////
62
63 char wbfs_slot_mode_info[WBFS_SLOT__MASK+1] = ".#!!" "-?!!" "-?!!" "-?!!";
64
65 ///////////////////////////////////////////////////////////////////////////////
66 ///////////////////////////////////////////////////////////////////////////////
67
wbfs_setup_inode_info(wbfs_t * p,wbfs_inode_info_t * ii,bool is_valid,int is_changed)68 be64_t wbfs_setup_inode_info
69 ( wbfs_t * p, wbfs_inode_info_t * ii, bool is_valid, int is_changed )
70 {
71 ASSERT(p);
72 ASSERT(p->head);
73 ASSERT(ii);
74 ASSERT( sizeof(wbfs_inode_info_t) == WBFS_INODE_INFO_SIZE );
75
76 memcpy(ii,p->head,WBFS_INODE_INFO_HEAD_SIZE);
77 ii->info_version = htonl(WBFS_INODE_INFO_VERSION);
78
79 be64_t now = hton64(wbfs_time());
80
81 if (is_changed)
82 ii->ctime = ii->atime = now;
83
84 if (is_valid)
85 {
86 if ( !ntoh64(ii->itime) )
87 ii->itime = now;
88 if ( !ntoh64(ii->mtime) )
89 ii->mtime = now;
90 if ( !ntoh64(ii->ctime) )
91 ii->ctime = now;
92 if ( !ntoh64(ii->atime) )
93 ii->atime = now;
94 ii->dtime = 0;
95 }
96 else if ( !ntoh64(ii->dtime) )
97 ii->dtime = now;
98
99 return now;
100 }
101
102 ///////////////////////////////////////////////////////////////////////////////
103
wbfs_is_inode_info_valid(const wbfs_t * p,const wbfs_inode_info_t * ii)104 int wbfs_is_inode_info_valid
105 (
106 // if valid -> return WBFS_INODE_INFO_VERSION
107 // if invalid -> return 0
108
109 const wbfs_t * p, // NULL or WBFS
110 const wbfs_inode_info_t * ii // NULL or inode pointer
111 )
112 {
113 DASSERT( sizeof(wbfs_inode_info_t) == WBFS_INODE_INFO_SIZE );
114
115 if (!ii)
116 return 0;
117
118 const u32 version = ntohl(ii->info_version);
119 if ( !version || version > WBFS_INODE_INFO_VERSION )
120 return 0;
121
122 if ( p && p->head )
123 return memcmp(ii,p->head,WBFS_INODE_INFO_CMP_SIZE) ? 0 : version;
124
125 return ii->magic == wbfs_htonl(WBFS_MAGIC) ? version : 0;
126 }
127
128 ///////////////////////////////////////////////////////////////////////////////
129 ///////////////////////////////////////////////////////////////////////////////
130
size_to_shift(u32 size)131 static u8 size_to_shift(u32 size)
132 {
133 u8 ret = 0;
134 while (size)
135 {
136 ret++;
137 size>>=1;
138 }
139 return ret-1;
140 }
141
142 //
143 ///////////////////////////////////////////////////////////////////////////////
144 #ifndef WIT // not used in WiT
145
wbfs_open_partition(rw_sector_callback_t read_hdsector,rw_sector_callback_t write_hdsector,void * callback_data,int hd_sector_size,int num_hd_sector,u32 part_lba,int reset)146 wbfs_t * wbfs_open_partition
147 (
148 rw_sector_callback_t read_hdsector,
149 rw_sector_callback_t write_hdsector,
150 void * callback_data,
151 int hd_sector_size,
152 int num_hd_sector,
153 u32 part_lba,
154 int reset
155 )
156 {
157 wbfs_param_t par;
158 memset(&par,0,sizeof(par));
159
160 par.read_hdsector = read_hdsector;
161 par.write_hdsector = write_hdsector;
162 par.callback_data = callback_data;
163 par.hd_sector_size = hd_sector_size;
164 par.num_hd_sector = num_hd_sector;
165 par.part_lba = part_lba;
166 par.reset = reset > 0;
167 par.clear_inodes = reset > 1;
168 par.setup_iinfo = reset > 2;
169 par.force_mode = force_mode > 0; // global parameter
170
171 return wbfs_open_partition_param(&par);
172 }
173
174 #endif // !WIT
175 ///////////////////////////////////////////////////////////////////////////////
176
wbfs_setup_lists(wbfs_t * p)177 void wbfs_setup_lists
178 (
179 wbfs_t * p // valid WBFS descriptor
180 )
181 {
182 DASSERT(p);
183
184 const size_t used_size = p->n_wbfs_sec + 32;
185 if (!p->used_block)
186 p->used_block = MALLOC(used_size);
187 memset(p->used_block,0,used_size);
188 p->used_block[0] = 0xff;
189
190 const size_t id_list_size = (p->max_disc+1) * sizeof(*p->id_list);
191 if (!p->id_list)
192 p->id_list = MALLOC(id_list_size);
193 memset(p->id_list,0,id_list_size);
194 }
195
196 ///////////////////////////////////////////////////////////////////////////////
197
wbfs_open_partition_param(wbfs_param_t * par)198 wbfs_t * wbfs_open_partition_param ( wbfs_param_t * par )
199 {
200 TRACE("LIBWBFS: +wbfs_open_partition_param()\n");
201 ASSERT(par);
202
203 //----- alloc mem
204
205 int hd_sector_size = par->hd_sector_size ? par->hd_sector_size : 512;
206 wbfs_head_t *head = wbfs_ioalloc(hd_sector_size);
207 wbfs_t *p = wbfs_malloc(sizeof(wbfs_t));
208
209 memset(p,0,sizeof(*p));
210
211 //----- store head and parameters
212
213 p->head = head;
214 p->part_lba = par->part_lba;
215 p->read_hdsector = par->read_hdsector;
216 p->write_hdsector = par->write_hdsector;
217 p->callback_data = par->callback_data;
218 p->balloc_mode = par->balloc_mode;
219
220 //----- init/load partition header
221
222 if ( par->reset > 0 )
223 {
224 // if reset: make some calculations and store the result in the header
225
226 wbfs_memset(head,0,hd_sector_size);
227 head->magic = wbfs_htonl(WBFS_MAGIC);
228 head->wbfs_version = WBFS_VERSION;
229 head->hd_sec_sz_s = size_to_shift(hd_sector_size);
230 hd_sector_size = 1 << head->hd_sec_sz_s;
231 head->n_hd_sec = wbfs_htonl(par->num_hd_sector);
232
233 if ( par->old_wii_sector_calc > 0 )
234 {
235 //*** this is the old calculation with rounding error
236 p->n_wii_sec = ( par->num_hd_sector / WII_SECTOR_SIZE) * hd_sector_size;
237 }
238 else
239 {
240 //*** but *here* we can/should use the correct one
241 p->n_wii_sec = par->num_hd_sector / ( WII_SECTOR_SIZE / hd_sector_size );
242 }
243
244 if ( par->wbfs_sector_size > 0 )
245 head->wbfs_sec_sz_s = size_to_shift(par->wbfs_sector_size);
246 else
247 head->wbfs_sec_sz_s
248 = wbfs_calc_size_shift( head->hd_sec_sz_s,
249 par->num_hd_sector,
250 par->old_wii_sector_calc );
251 }
252 else
253 {
254 // no reset: just load header
255
256 p->read_hdsector(p->callback_data,p->part_lba,1,head);
257 }
258
259 //----- validation tests
260
261 if ( head->magic != wbfs_htonl(WBFS_MAGIC) )
262 WBFS_ERROR("bad magic");
263
264 if ( par->force_mode <= 0 )
265 {
266 if ( hd_sector_size && head->hd_sec_sz_s != size_to_shift(hd_sector_size) )
267 WBFS_ERROR("hd sector size doesn't match");
268
269 if ( par->num_hd_sector && head->n_hd_sec != wbfs_htonl(par->num_hd_sector) )
270 WBFS_ERROR("hd num sector doesn't match");
271 }
272
273
274 //----- setup wbfs geometry
275
276 wbfs_calc_geometry(p,
277 wbfs_ntohl(head->n_hd_sec),
278 1 << head->hd_sec_sz_s,
279 1 << head->wbfs_sec_sz_s );
280
281
282 //----- etc
283
284 p->tmp_buffer = wbfs_ioalloc(p->hd_sec_sz);
285
286 if ( par->reset > 0 )
287 {
288 if ( par->setup_iinfo > 0 )
289 {
290 // build an empty inode with a valid inode_info and write it to all slots.
291
292 const int disc_info_sz_lba = p->disc_info_sz >> p->hd_sec_sz_s;
293 wbfs_disc_info_t * info = wbfs_ioalloc(p->disc_info_sz);
294 memset(info,0,p->disc_info_sz);
295 wbfs_inode_info_t * iinfo = wbfs_get_inode_info(p,info,0);
296 wbfs_setup_inode_info(p,&par->iinfo,0,0);
297 memcpy(iinfo,&par->iinfo,sizeof(*iinfo));
298
299 int slot;
300 for ( slot = 0; slot < p->max_disc; slot++ )
301 {
302 const int lba = p->part_lba + 1 + slot * disc_info_sz_lba;
303 p->write_hdsector(p->callback_data,lba,disc_info_sz_lba,info);
304 }
305
306 wbfs_iofree(info);
307 }
308 else if ( par->clear_inodes > 0 )
309 {
310 // clear all disc header, but we are nice to sparse files
311 // -> read the data first and only if not zeroed we write back
312
313 const int disc_info_sz_lba = p->disc_info_sz >> p->hd_sec_sz_s;
314 wbfs_disc_info_t * info = wbfs_ioalloc(p->disc_info_sz);
315
316 int slot;
317 for ( slot = 0; slot < p->max_disc; slot++ )
318 {
319 const int lba = p->part_lba + 1 + slot * disc_info_sz_lba;
320 p->read_hdsector(p->callback_data,lba,disc_info_sz_lba,info);
321
322 const u32 * ptr = (u32*)info;
323 const u32 * end = ptr + p->disc_info_sz/sizeof(*ptr);
324 while ( ptr < end )
325 {
326 if (*ptr++)
327 {
328 memset(info,0,p->disc_info_sz);
329 p->write_hdsector(p->callback_data,lba,disc_info_sz_lba,info);
330 break;
331 }
332 //TRACE("%p %p %p\n",info,ptr,end);
333 }
334 }
335
336 wbfs_iofree(info);
337 }
338 }
339
340
341 //----- all done, terminate
342
343 if ( par->reset > 0 )
344 {
345 wbfs_setup_lists(p);
346 p->is_dirty = p->used_block_dirty = true;
347 wbfs_sync(p);
348 }
349 else
350 {
351 if ( wbfs_calc_used_blocks(p,true,false,0,0) )
352 goto error;
353
354 #if 0 && defined(DEBUG) && defined(TEST)
355 wbfs_print_block_usage(stdout,3,p,false);
356 #endif
357 }
358
359 return p;
360
361
362 //----- error handling
363
364 error:
365 p->is_dirty = false;
366 wbfs_close(p);
367 wbfs_iofree(head);
368 return 0;
369 }
370
371 //
372 ///////////////////////////////////////////////////////////////////////////////
373 // public calculation helpers
374
wbfs_calc_size_shift(u32 hd_sec_sz_s,u32 num_hd_sector,int old_wii_sector_calc)375 int wbfs_calc_size_shift
376 ( u32 hd_sec_sz_s, u32 num_hd_sector, int old_wii_sector_calc )
377 {
378 const u32 hd_sector_size = 1 << hd_sec_sz_s;
379
380 const u32 n_wii_sec = old_wii_sector_calc > 0
381 //*** this is the old calculation with rounding error
382 ? ( num_hd_sector / WII_SECTOR_SIZE) * hd_sector_size
383 //*** but *here* we can/should use the correct one
384 : num_hd_sector / ( WII_SECTOR_SIZE / hd_sector_size );
385
386 // ensure that wbfs_sec_sz is big enough to address every blocks using 16 bits
387 // choose minimum wblk_sz that fits this partition size
388 // the max value chooses the maximal supported partition size
389 // - start_value < 6 ==> n_wbfs_sec_per_disc becomes to large
390
391 DASSERT( ( 1 << WII_SECTOR_SIZE_SHIFT + WBFS_MIN_SECTOR_SHIFT ) == WBFS_MIN_SECTOR_SIZE );
392 DASSERT( ( 1 << WII_SECTOR_SIZE_SHIFT + WBFS_MAX_SECTOR_SHIFT ) == WBFS_MAX_SECTOR_SIZE );
393
394 int shift_count;
395 for ( shift_count = WBFS_MIN_SECTOR_SHIFT;
396 shift_count <= WBFS_MAX_SECTOR_SHIFT;
397 shift_count++
398 )
399 {
400 // ensure that wbfs_sec_sz is big enough to address every blocks using 16 bits
401 if ( n_wii_sec < (u32)WBFS_MAX_SECTORS << shift_count )
402 break;
403 }
404
405 return shift_count + WII_SECTOR_SIZE_SHIFT;
406 }
407
408 ///////////////////////////////////////////////////////////////////////////////
409
wbfs_calc_sect_size(u64 total_size,u32 hd_sec_size)410 u32 wbfs_calc_sect_size ( u64 total_size, u32 hd_sec_size )
411 {
412 const u32 hd_sec_sz_s = size_to_shift(hd_sec_size);
413 hd_sec_size = (u32)1 << hd_sec_sz_s;
414 return (u32)1 << wbfs_calc_size_shift(hd_sec_sz_s,total_size/hd_sec_size,0);
415 }
416
417 ///////////////////////////////////////////////////////////////////////////////
418
wbfs_calc_geometry(wbfs_t * p,u32 n_hd_sec,u32 hd_sec_sz,u32 wbfs_sec_sz)419 void wbfs_calc_geometry
420 (
421 wbfs_t * p, // pointer to wbfs_t, p->head must be NULL or valid
422 u32 n_hd_sec, // total number of hd_sec in partition
423 u32 hd_sec_sz, // size of a hd/partition sector
424 u32 wbfs_sec_sz // size of a wbfs sector
425 )
426 {
427 ASSERT(p);
428
429 //----- parameter calculations & corrections
430
431 const u32 hd_sec_sz_s = size_to_shift(hd_sec_sz);
432 hd_sec_sz = 1 << hd_sec_sz_s;
433
434 const u32 wbfs_sec_sz_s = size_to_shift(wbfs_sec_sz);
435 wbfs_sec_sz = 1 << wbfs_sec_sz_s;
436
437 //----- setup header if not NULL
438
439 if (p->head)
440 {
441 memset(p->head,0,sizeof(p->head));
442 p->head->magic = wbfs_htonl(WBFS_MAGIC);
443 p->head->n_hd_sec = wbfs_htonl(n_hd_sec);
444 p->head->hd_sec_sz_s = hd_sec_sz_s;
445 p->head->wbfs_sec_sz_s = wbfs_sec_sz_s;
446 p->head->wbfs_version = WBFS_VERSION;
447 }
448
449 //----- setup some wii constants
450
451 p->wii_sec_sz = WII_SECTOR_SIZE;
452 p->wii_sec_sz_s = WII_SECTOR_SIZE_SHIFT;
453 p->n_wii_sec_per_disc = WII_MAX_SECTORS;
454
455 //----- transfer parameters
456
457 p->hd_sec_sz_s = hd_sec_sz_s;
458 p->hd_sec_sz = hd_sec_sz;
459 p->n_hd_sec = n_hd_sec;
460
461 p->wbfs_sec_sz_s = wbfs_sec_sz_s;
462 p->wbfs_sec_sz = wbfs_sec_sz;
463
464 //----- base calculations
465
466 // ************************************************************************
467 // *** This calculation has a rounding bug. But we must leave it here ***
468 // *** because 'n_wbfs_sec' & 'freeblks_lba' are based in this value. ***
469 // ************************************************************************
470
471 p->n_wii_sec = ( p->n_hd_sec / p->wii_sec_sz ) * p->hd_sec_sz;
472 p->n_wbfs_sec = p->n_wii_sec >> ( p->wbfs_sec_sz_s - p->wii_sec_sz_s );
473 p->n_wbfs_sec_per_disc
474 = p->n_wii_sec_per_disc >> ( p->wbfs_sec_sz_s - p->wii_sec_sz_s );
475 p->disc_info_sz = ALIGN_LBA( sizeof(wbfs_disc_info_t) + p->n_wbfs_sec_per_disc*2 );
476
477 //----- 'free blocks table' calculations
478
479 const u32 fb_memsize= ALIGN_LBA(p->n_wbfs_sec/8); // memory size of 'freeblks'
480 p->freeblks_lba = ( p->wbfs_sec_sz - p->n_wbfs_sec / 8 ) >> p->hd_sec_sz_s;
481 p->freeblks_lba_count
482 = fb_memsize >> p->hd_sec_sz_s;
483
484 //----- here we correct the previous wrong calulations
485
486 p->n_wii_sec = p->n_hd_sec / ( p->wii_sec_sz / p->hd_sec_sz );
487 const u32 n_wbfs_sec= p->n_wii_sec >> ( p->wbfs_sec_sz_s - p->wii_sec_sz_s );
488 p->n_wbfs_sec = n_wbfs_sec < WBFS_MAX_SECTORS
489 ? n_wbfs_sec : WBFS_MAX_SECTORS;
490
491 //----- calculate and fix the needed space for free blocks table
492
493 p->freeblks_size4 = ( p->n_wbfs_sec-1 + 31 ) / 32;
494 if ( p->freeblks_size4 > fb_memsize/4 )
495 {
496 // not enough memory to store complete free blocks table :(
497 p->freeblks_size4 = fb_memsize/4;
498
499 // fix the number of WBFS sectors too
500 const u32 max_sec = p->freeblks_size4 * 32 + 1; // remember: 1 based
501 if ( p->n_wbfs_sec > max_sec )
502 p->n_wbfs_sec = max_sec;
503 }
504 p->freeblks_mask = ( 1ull << ( (p->n_wbfs_sec-1) & 31 )) - 1;
505 if (!p->freeblks_mask)
506 p->freeblks_mask = ~(u32)0;
507
508 //----- calculate max_disc
509
510 p->max_disc = ( p->freeblks_lba - 1 ) / ( p->disc_info_sz >> p->hd_sec_sz_s );
511 if ( p->max_disc > p->hd_sec_sz - sizeof(wbfs_head_t) )
512 p->max_disc = p->hd_sec_sz - sizeof(wbfs_head_t);
513 }
514
515 //
516 ///////////////////////////////////////////////////////////////////////////////
517
wbfs_sync(wbfs_t * p)518 void wbfs_sync ( wbfs_t * p )
519 {
520 // writes wbfs header and free blocks to hardisk
521
522 TRACE("LIBWBFS: +wbfs_sync(%p) wr_hds=%p, head=%p, freeblks=%p\n",
523 p, p->write_hdsector, p->head, p->freeblks );
524
525 if (p->write_hdsector)
526 {
527 p->write_hdsector ( p->callback_data, p->part_lba, 1, p->head );
528
529 if ( p->used_block && p->used_block_dirty )
530 {
531 wbfs_load_freeblocks(p);
532 if (p->freeblks)
533 p->write_hdsector( p->callback_data,
534 p->part_lba + p->freeblks_lba,
535 p->freeblks_lba_count,
536 p->freeblks );
537 p->used_block_dirty = false;
538 }
539
540 p->is_dirty = false;
541 }
542 }
543
544 ///////////////////////////////////////////////////////////////////////////////
545
wbfs_close(wbfs_t * p)546 void wbfs_close ( wbfs_t * p )
547 {
548 TRACE("LIBWBFS: +wbfs_close(%p) disc_open=%d, head=%p, freeblks=%p\n",
549 p, p->n_disc_open, p->head, p->freeblks );
550
551 if (p->n_disc_open)
552 WBFS_ERROR("trying to close wbfs while discs still open");
553
554 if (p->is_dirty)
555 wbfs_sync(p);
556
557 wbfs_free_freeblocks(p);
558 wbfs_iofree(p->block0);
559 wbfs_free(p->used_block);
560 wbfs_free(p->id_list);
561 wbfs_iofree(p->head);
562 wbfs_iofree(p->tmp_buffer);
563 wbfs_free(p);
564
565 error:
566 return;
567 }
568
569 //
570 ///////////////////////////////////////////////////////////////////////////////
571 ///////////////////////////////////////////////////////////////////////////////
572
wbfs_open_disc_by_id6(wbfs_t * p,u8 * discid)573 wbfs_disc_t * wbfs_open_disc_by_id6 ( wbfs_t* p, u8 * discid )
574 {
575 ASSERT(p);
576 ASSERT(discid);
577
578 const int slot = wbfs_find_slot(p,discid);
579 return slot < 0 ? 0 : wbfs_open_disc_by_slot(p,slot,0);
580 }
581
582 ///////////////////////////////////////////////////////////////////////////////
583
wbfs_open_disc_by_info(wbfs_t * p,u32 slot,wbfs_disc_info_t * info,int force_open)584 static wbfs_disc_t * wbfs_open_disc_by_info
585 ( wbfs_t * p, u32 slot, wbfs_disc_info_t * info, int force_open )
586 {
587 ASSERT(p);
588 ASSERT( slot >= 0 );
589 ASSERT(info);
590
591 wbfs_disc_t * d = wbfs_calloc(1,sizeof(*d));
592 d->p = p;
593 d->slot = slot;
594 d->header = info;
595
596 d->is_used = p->head->disc_table[slot] != WBFS_SLOT_FREE;
597 if ( *d->header->dhead )
598 {
599 d->disc_type = get_header_disc_type((wd_header_t*)d->header->dhead,&d->disc_attrib);
600 const u32 wii_magic = be32(d->header->dhead+WII_MAGIC_OFF);
601 const u32 gc_magic = be32(d->header->dhead+GC_MAGIC_OFF);
602 noTRACE("MAGIC: %08x %08x => %d %d\n",
603 wii_magic, gc_magic, wii_magic == WII_MAGIC, gc_magic == GC_MAGIC );
604 d->is_valid = wii_magic == WII_MAGIC || gc_magic == GC_MAGIC;
605 d->is_deleted = wii_magic == WII_MAGIC_DELETED;
606 }
607 else
608 d->is_valid = d->is_deleted = false;
609
610 if ( !force_open && !d->is_valid )
611 {
612 p->head->disc_table[slot] = WBFS_SLOT_FREE;
613 wbfs_free(info);
614 wbfs_free(d);
615 return 0;
616 }
617
618 wbfs_get_disc_inode_info(d,1);
619 p->n_disc_open++;
620 return d;
621 }
622
623 ///////////////////////////////////////////////////////////////////////////////
624
wbfs_open_disc_by_slot(wbfs_t * p,u32 slot,int force_open)625 wbfs_disc_t * wbfs_open_disc_by_slot ( wbfs_t * p, u32 slot, int force_open )
626 {
627 ASSERT(p);
628 TRACE("LIBWBFS: wbfs_open_disc_by_slot(%p,slot=%u,force=%d) max=%u, disctab=%u\n",
629 p, slot, p->max_disc, p->head->disc_table[slot], force_open );
630
631 if ( slot >= p->max_disc || !p->head->disc_table[slot] && !force_open )
632 return 0;
633
634 wbfs_disc_info_t * info = wbfs_ioalloc(p->disc_info_sz);
635
636 const u32 disc_info_sz_lba = p->disc_info_sz >> p->hd_sec_sz_s;
637 if ( p->read_hdsector (
638 p->callback_data,
639 p->part_lba + 1 + slot * disc_info_sz_lba,
640 disc_info_sz_lba,
641 info ) )
642 {
643 wbfs_free(info);
644 return 0;
645 }
646
647 return wbfs_open_disc_by_info(p,slot,info,force_open);
648 }
649
650 ///////////////////////////////////////////////////////////////////////////////
651
wbfs_create_disc(wbfs_t * p,const void * disc_header,const void * disc_id)652 wbfs_disc_t * wbfs_create_disc
653 (
654 wbfs_t * p, // valid WBFS descriptor
655 const void * disc_header, // NULL or disc header to copy
656 const void * disc_id // NULL or ID6: check non existence
657 // disc_id overwrites the id of disc_header
658 )
659 {
660 ASSERT(p);
661
662 if ( !disc_id && disc_header )
663 disc_id = disc_header;
664
665 if (disc_id)
666 {
667 int slot = wbfs_find_slot(p,disc_id);
668 if ( slot >= 0 )
669 {
670 wbfs_error("Disc with id '%s' already exists.",
671 wd_print_id(disc_id,6,0));
672 return 0;
673 }
674 }
675
676 //----- find a free slot
677
678 int slot;
679 for ( slot = 0; slot < p->max_disc; slot++ )
680 if (!p->head->disc_table[slot])
681 break;
682
683 if ( slot == p->max_disc )
684 {
685 wbfs_error("Limit of %u discs alreday reached.",p->max_disc);
686 return 0;
687 }
688
689
690 //----- open slot
691
692 p->head->disc_table[slot] = WBFS_SLOT_VALID;
693 p->is_dirty = true;
694
695 wbfs_disc_info_t * info = wbfs_ioalloc(p->disc_info_sz);
696 memset(info,0,p->disc_info_sz);
697 wd_header_t * dhead = (wd_header_t*)info->dhead;
698 dhead->wii_magic = htonl(WII_MAGIC);
699
700 if (disc_header)
701 memcpy(info->dhead,disc_header,sizeof(info->dhead));
702
703 if (disc_id)
704 wd_patch_id(info->dhead,info->dhead,disc_id,6);
705
706 wbfs_disc_t * disc = wbfs_open_disc_by_info(p,slot,info,true);
707 if (disc)
708 disc->is_creating = disc->is_dirty = true;
709 return disc;
710 }
711
712 ///////////////////////////////////////////////////////////////////////////////
713
wbfs_sync_disc_header(wbfs_disc_t * d)714 int wbfs_sync_disc_header ( wbfs_disc_t * d )
715 {
716 DASSERT(d);
717 if ( !d || !d->p || !d->header )
718 return 1;
719
720 d->is_dirty = false;
721 wbfs_t * p = d->p;
722 const u32 disc_info_sz_lba = p->disc_info_sz >> p->hd_sec_sz_s;
723 return p->write_hdsector (
724 p->callback_data,
725 p->part_lba + 1 + d->slot * disc_info_sz_lba,
726 disc_info_sz_lba,
727 d->header );
728 }
729
730 ///////////////////////////////////////////////////////////////////////////////
731
wbfs_close_disc(wbfs_disc_t * d)732 void wbfs_close_disc ( wbfs_disc_t * d )
733 {
734 ASSERT( d );
735 ASSERT( d->header );
736 ASSERT( d->p );
737 ASSERT( d->p->n_disc_open > 0 );
738
739 if (d->is_dirty)
740 wbfs_sync_disc_header(d);
741
742 d->p->n_disc_open--;
743 wbfs_iofree(d->header);
744 wbfs_free(d);
745 }
746
747 ///////////////////////////////////////////////////////////////////////////////
748
wbfs_get_inode_info(wbfs_t * p,wbfs_disc_info_t * info,int clear_mode)749 wbfs_inode_info_t * wbfs_get_inode_info
750 ( wbfs_t *p, wbfs_disc_info_t * info, int clear_mode )
751 {
752 ASSERT(p);
753 ASSERT(info);
754 wbfs_inode_info_t * iinfo
755 = (wbfs_inode_info_t*)(info->dhead + WBFS_INODE_INFO_OFF);
756
757 if ( clear_mode>1 || clear_mode && !wbfs_is_inode_info_valid(p,iinfo) )
758 memset(iinfo,0,sizeof(wbfs_inode_info_t));
759 return iinfo;
760 }
761
762 ///////////////////////////////////////////////////////////////////////////////
763
wbfs_get_disc_inode_info(wbfs_disc_t * d,int clear_mode)764 wbfs_inode_info_t * wbfs_get_disc_inode_info ( wbfs_disc_t * d, int clear_mode )
765 {
766 ASSERT(d);
767 wbfs_inode_info_t * iinfo = wbfs_get_inode_info(d->p,d->header,clear_mode);
768 d->is_iinfo_valid = wbfs_is_inode_info_valid(d->p,iinfo) != 0;
769 return iinfo;
770 }
771
772 ///////////////////////////////////////////////////////////////////////////////
773
wbfs_get_fragments(const u16 * wlba_tab,uint tab_length,uint * disc_blocks)774 uint wbfs_get_fragments
775 (
776 const u16 * wlba_tab, // valid wlba table in network byte order
777 uint tab_length, // length of 'wlba_tab'
778 uint * disc_blocks // not NULL: store number of disc blocks
779 )
780 {
781 int bl, next_block = -1, last_bl = 0, n_frag = 0;
782 for ( bl = 0; bl < tab_length; bl++ )
783 {
784 int block = ntohs(wlba_tab[bl]);
785 if (block)
786 {
787 if ( block != next_block )
788 n_frag++;
789 next_block = block + 1;
790 last_bl = bl;
791 }
792 }
793 TRACE("WBFS-CALC-FRAG: %u, blocks = %u/%u\n", n_frag, last_bl+1, tab_length );
794
795 if (disc_blocks)
796 *disc_blocks = last_bl + 1;
797 return n_frag;
798 }
799
800 ///////////////////////////////////////////////////////////////////////////////
801
wbfs_get_disc_fragments(wbfs_disc_t * d,uint * disc_blocks)802 uint wbfs_get_disc_fragments
803 (
804 wbfs_disc_t *d, // valid wbfs disc
805 uint * disc_blocks // not NULL: store number of disc blocks
806 )
807 {
808 DASSERT(d);
809 DASSERT(d->p);
810 if ( !d->n_fragments && d->header )
811 {
812 d->n_fragments
813 = wbfs_get_fragments( d->header->wlba_table,
814 d->p->n_wbfs_sec_per_disc, &d->disc_blocks );
815 }
816 if (disc_blocks)
817 *disc_blocks = d->disc_blocks;
818 return d->n_fragments;
819 }
820
821 ///////////////////////////////////////////////////////////////////////////////
822 // rename a disc
823
wbfs_rename_disc(wbfs_disc_t * d,const char * new_id,const char * new_title,int chg_wbfs_head,int chg_iso_head)824 int wbfs_rename_disc
825 (
826 wbfs_disc_t * d, // pointer to an open disc
827 const char * new_id, // if !NULL: take the first 6 chars as ID
828 const char * new_title, // if !NULL: take the first 0x39 chars as title
829 int chg_wbfs_head, // if !0: change ID/title of WBFS header
830 int chg_iso_head // if !0: change ID/title of ISO header
831 )
832 {
833 ASSERT(d);
834 ASSERT(d->p);
835 ASSERT(d->header);
836
837 wbfs_t * p = d->p;
838
839 wbfs_inode_info_t * iinfo = wbfs_get_disc_inode_info(d,1);
840 const be64_t now = wbfs_setup_inode_info(p,iinfo,d->is_valid,0);
841
842 int do_sync = 0;
843 if ( chg_wbfs_head
844 && wd_rename(d->header->dhead,new_id,new_title) )
845 {
846 iinfo->ctime = iinfo->atime = now;
847 do_sync++;
848 }
849
850 if ( chg_iso_head )
851 {
852 u16 wlba = ntohs(d->header->wlba_table[0]);
853 if (wlba)
854 {
855 u8 * tmpbuf = p->tmp_buffer;
856 ASSERT(tmpbuf);
857 const u32 lba = wlba << ( p->wbfs_sec_sz_s - p->hd_sec_sz_s );
858 int err = p->read_hdsector( p->callback_data, lba, 1, tmpbuf );
859 if (err)
860 return err;
861 if (wd_rename(tmpbuf,new_id,new_title))
862 {
863 iinfo->mtime = iinfo->ctime = iinfo->atime = now;
864 err = p->write_hdsector( p->callback_data, lba, 1, tmpbuf );
865 if (err)
866 return err;
867 do_sync++;
868 }
869 }
870 }
871
872 if (do_sync)
873 {
874 TRACE("wbfs_rename_disc() now=%llu i=%llu m=%llu c=%llu a=%llu d=%llu\n",
875 ntoh64(now),
876 ntoh64(iinfo->itime),
877 ntoh64(iinfo->mtime),
878 ntoh64(iinfo->ctime),
879 ntoh64(iinfo->atime),
880 ntoh64(iinfo->dtime));
881
882 const int err = wbfs_sync_disc_header(d);
883 if (err)
884 return err;
885 }
886
887 return 0;
888 }
889
890 ///////////////////////////////////////////////////////////////////////////////
891
wbfs_touch_disc(wbfs_disc_t * d,u64 itime,u64 mtime,u64 ctime,u64 atime)892 int wbfs_touch_disc
893 (
894 wbfs_disc_t * d, // pointer to an open disc
895 u64 itime, // if != 0: new itime
896 u64 mtime, // if != 0: new mtime
897 u64 ctime, // if != 0: new ctime
898 u64 atime // if != 0: new atime
899 )
900 {
901 ASSERT(d);
902 ASSERT(d->p);
903 ASSERT(d->header);
904
905 TRACE("wbfs_touch_disc(%p,%llu,%llu,%llu,%llu)\n",d,itime,mtime,ctime,atime);
906
907 wbfs_inode_info_t * iinfo = wbfs_get_disc_inode_info(d,1);
908 wbfs_setup_inode_info(d->p,iinfo,d->is_valid,0);
909
910 if (itime)
911 iinfo->itime = hton64(itime);
912 if (mtime)
913 iinfo->mtime = hton64(mtime);
914 if (ctime)
915 iinfo->ctime = hton64(ctime);
916 if (atime)
917 iinfo->atime = hton64(atime);
918
919 return wbfs_sync_disc_header(d);
920 }
921
922 ///////////////////////////////////////////////////////////////////////////////
923
wbfs_print_block_usage(FILE * f,int indent,const wbfs_t * p,bool print_all)924 void wbfs_print_block_usage
925 (
926 FILE * f, // valid output file
927 int indent, // indention of the output
928 const wbfs_t * p, // valid WBFS descriptor
929 bool print_all // false: ignore const lines
930 )
931 {
932 DASSERT(p);
933 DASSERT(p->used_block);
934 wbfs_print_usage_tab( f, indent, p->used_block, p->n_wbfs_sec,
935 p->wbfs_sec_sz, print_all );
936 }
937
938 ///////////////////////////////////////////////////////////////////////////////
939
940 const char wbfs_usage_name_tab[256] =
941 {
942 ".x23456789ABCDEFGHIJKLMNOPQRSTUV"
943 "WXYZ++++++++++++++++++++++++++++"
944 "++++++++++++++++++++++++++++++++"
945 "+++++++++++++++++++++++++++++++*"
946
947 "0123456789ABCDEFGHIJKLMNOPQRSTUV"
948 "WXYZ++++++++++++++++++++++++++++"
949 "++++++++++++++++++++++++++++++++"
950 "+++++++++++++++++++++++++++++++h"
951 };
952
953 //-----------------------------------------------------------------------------
954
wbfs_print_usage_tab(FILE * f,int indent,const u8 * used_block,u32 block_used_sz,u32 sector_size,bool print_all)955 void wbfs_print_usage_tab
956 (
957 FILE * f, // valid output file
958 int indent, // indention of the output
959 const u8 * used_block, // valid pointer to usage table
960 u32 block_used_sz, // size of 'used_block'
961 u32 sector_size, // wbfs sector size
962 bool print_all // false: ignore const lines
963 )
964 {
965 wd_print_byte_tab( f, indent, used_block, block_used_sz, block_used_sz,
966 sector_size, wbfs_usage_name_tab, print_all );
967 }
968
969 ///////////////////////////////////////////////////////////////////////////////
970
wbfs_count_discs(wbfs_t * p)971 u32 wbfs_count_discs ( wbfs_t * p )
972 {
973 u32 i,count=0;
974 for ( i = 0; i < p->max_disc; i++ )
975 if (p->head->disc_table[i])
976 count++;
977 return count;
978 }
979
980 ///////////////////////////////////////////////////////////////////////////////
981
wbfs_sector_used(wbfs_t * p,wbfs_disc_info_t * di)982 static u32 wbfs_sector_used ( wbfs_t * p, wbfs_disc_info_t * di )
983 {
984 u32 tot_blk = 0, j;
985 for ( j = 0; j < p->n_wbfs_sec_per_disc; j++ )
986 if (wbfs_ntohs(di->wlba_table[j]))
987 tot_blk++;
988 return tot_blk;
989 }
990
991 ///////////////////////////////////////////////////////////////////////////////
992
wbfs_get_disc_info(wbfs_t * p,u32 index,u8 * header,int header_size,u32 * slot_found,wd_disc_type_t * disc_type,wd_disc_attrib_t * disc_attrib,u32 * size4,u32 * n_fragments)993 enumError wbfs_get_disc_info
994 (
995 wbfs_t * p, // valid wbfs descriptor
996 u32 index, // disc index: 0 .. num_dics-1
997 u8 * header, // header to store data
998 int header_size, // size of 'header'
999 u32 * slot_found, // not NULL: store slot of found disc
1000 wd_disc_type_t * disc_type, // not NULL: store disc type
1001 wd_disc_attrib_t * disc_attrib, // not NULL: store disc attrib
1002 u32 * size4, // not NULL: store 'size>>2' of found disc
1003 u32 * n_fragments // number of wbfs fragments
1004 )
1005 {
1006 u32 slot, count = 0;
1007 for( slot = 0; slot < p->max_disc; slot++ )
1008 if (p->head->disc_table[slot])
1009 if ( count++ == index )
1010 {
1011 if (slot_found)
1012 *slot_found = slot;
1013 return wbfs_get_disc_info_by_slot(p,slot,header,header_size,
1014 disc_type,disc_attrib,
1015 size4,n_fragments);
1016 }
1017 return ERR_WDISC_NOT_FOUND;
1018 }
1019
1020 ///////////////////////////////////////////////////////////////////////////////
1021
wbfs_get_disc_info_by_slot(wbfs_t * p,u32 slot,u8 * header,int header_size,wd_disc_type_t * disc_type,wd_disc_attrib_t * disc_attrib,u32 * size4,u32 * n_fragments)1022 enumError wbfs_get_disc_info_by_slot
1023 (
1024 wbfs_t * p, // valid wbfs descriptor
1025 u32 slot, // disc index: 0 .. num_dics-1
1026 u8 * header, // not NULL: header to store data
1027 int header_size, // size of 'header'
1028 wd_disc_type_t * disc_type, // not NULL: store disc type
1029 wd_disc_attrib_t * disc_attrib, // not NULL: store disc attrib
1030 u32 * size4, // not NULL: store 'size>>2' of found disc
1031 u32 * n_fragments // number of wbfs fragments
1032 )
1033 {
1034 ASSERT(p);
1035 if ( slot >= p->max_disc || !p->head->disc_table[slot] )
1036 return ERR_WDISC_NOT_FOUND;
1037
1038 const u32 disc_info_sz_lba = p->disc_info_sz >> p->hd_sec_sz_s;
1039 p->read_hdsector( p->callback_data,
1040 p->part_lba + 1 + slot * disc_info_sz_lba,
1041 1,
1042 p->tmp_buffer );
1043
1044
1045 const u32 wii_magic = be32(p->tmp_buffer+WII_MAGIC_OFF);
1046 const u32 gc_magic = be32(p->tmp_buffer+GC_MAGIC_OFF);
1047 TRACE("MAGIC: %08x %08x => %d %d\n",
1048 wii_magic, gc_magic, wii_magic == WII_MAGIC, gc_magic == GC_MAGIC );
1049
1050 if ( wii_magic != WII_MAGIC && gc_magic != GC_MAGIC )
1051 {
1052 p->head->disc_table[slot] = WBFS_SLOT_FREE;
1053 return ERR_WARNING;
1054 }
1055
1056 if (header)
1057 {
1058 if (header_size > (int)p->hd_sec_sz)
1059 header_size = p->hd_sec_sz;
1060 memcpy( header, p->tmp_buffer, header_size );
1061 }
1062
1063 if ( disc_type || disc_attrib )
1064 {
1065 const wd_disc_type_t dt
1066 = get_header_disc_type((wd_header_t*)p->tmp_buffer,disc_attrib);
1067 if (disc_type)
1068 *disc_type = dt;
1069 }
1070
1071 if ( size4 || n_fragments )
1072 {
1073 u32 sec_used;
1074 wbfs_disc_info_t *header = wbfs_ioalloc(p->disc_info_sz);
1075
1076 p->read_hdsector ( p->callback_data,
1077 p->part_lba + 1 + slot * disc_info_sz_lba,
1078 disc_info_sz_lba,
1079 header );
1080
1081 sec_used = wbfs_sector_used(p,header);
1082 if (size4)
1083 *size4 = sec_used << (p->wbfs_sec_sz_s-2);
1084 if (n_fragments)
1085 *n_fragments = wbfs_get_fragments( header->wlba_table,
1086 p->n_wbfs_sec_per_disc, 0 );
1087 wbfs_iofree(header);
1088 }
1089 return ERR_OK;
1090 }
1091
1092 ///////////////////////////////////////////////////////////////////////////////
1093
wbfs_load_id_list(wbfs_t * p,int force_reload)1094 id6_t * wbfs_load_id_list ( wbfs_t * p, int force_reload )
1095 {
1096 ASSERT(p);
1097 ASSERT(p->head);
1098 ASSERT(p->tmp_buffer);
1099 if ( p->id_list && !force_reload )
1100 return p->id_list;
1101
1102 const int id_item_size = sizeof(*p->id_list);
1103 const int id_list_size = (p->max_disc+1) * id_item_size;
1104 const u32 disc_info_sz_lba = p->disc_info_sz >> p->hd_sec_sz_s;
1105
1106 TRACE("LIBWBFS: +wbfs_load_id_list(%p,%d) id_list_size=%u*%u=%d\n",
1107 p, force_reload, p->max_disc, id_item_size, id_list_size );
1108
1109 if (!p->id_list)
1110 {
1111 TRACE("MALLOC id_list = %d * (%d+1) = %d\n",
1112 id_item_size, p->max_disc, id_list_size );
1113 p->id_list = wbfs_malloc(id_list_size);
1114 }
1115 memset(p->id_list,0,id_list_size);
1116
1117 u32 slot;
1118 for ( slot = 0; slot < p->max_disc; slot++ )
1119 if (p->head->disc_table[slot])
1120 {
1121 p->read_hdsector(p->callback_data,
1122 p->part_lba + 1 + slot * disc_info_sz_lba,
1123 1, p->tmp_buffer );
1124 TRACE(" - slot #%03u: %.6s\n",slot,p->tmp_buffer);
1125 memcpy(p->id_list[slot],p->tmp_buffer,id_item_size);
1126 }
1127
1128 return p->id_list;
1129 }
1130
1131 //
1132 ///////////////////////////////////////////////////////////////////////////////
1133
wbfs_find_slot(wbfs_t * p,const u8 * disc_id)1134 int wbfs_find_slot ( wbfs_t * p, const u8 * disc_id )
1135 {
1136 ASSERT(p);
1137 TRACE("LIBWBFS: +wbfs_find_slot(%p,%.6s)\n",p,disc_id);
1138
1139 wbfs_load_id_list(p,0);
1140 ASSERT(p->id_list);
1141
1142 const int id_item_size = sizeof(*p->id_list);
1143
1144 u32 slot;
1145 for ( slot = 0; slot < p->max_disc; slot++ )
1146 if ( p->head->disc_table[slot]
1147 && !memcmp(p->id_list[slot],disc_id,id_item_size) )
1148 {
1149 TRACE("LIBWBFS: -wbfs_find_slot() slot=%u\n",slot);
1150 return slot;
1151 }
1152
1153 TRACE("LIBWBFS: -wbfs_find_slot() ID_NOT_FOUND\n");
1154 return -1;
1155 }
1156
1157 ///////////////////////////////////////////////////////////////////////////////
1158
wbfs_free_freeblocks(wbfs_t * p)1159 u32 * wbfs_free_freeblocks ( wbfs_t * p )
1160 {
1161 DASSERT(p);
1162
1163 if (p->block0)
1164 {
1165 if ( p->freeblks && ( (u8*)p->freeblks < p->block0
1166 || (u8*)p->freeblks > p->block0 + p->wbfs_sec_sz ))
1167 {
1168 wbfs_iofree(p->freeblks);
1169 }
1170 p->freeblks = (u32*)( p->block0
1171 + ( p->part_lba + p->freeblks_lba ) * p->hd_sec_sz );
1172 return p->freeblks;
1173 }
1174
1175 if (p->freeblks)
1176 {
1177 wbfs_iofree(p->freeblks);
1178 p->freeblks = 0;
1179 }
1180
1181 return 0;
1182 }
1183
1184 ///////////////////////////////////////////////////////////////////////////////
1185
wbfs_load_freeblocks(wbfs_t * p)1186 u32 * wbfs_load_freeblocks ( wbfs_t * p )
1187 {
1188 DASSERT(p);
1189
1190 if (p->block0)
1191 wbfs_free_freeblocks(p); // setup 'freeblks' pointer from block0
1192
1193 bool dirty = p->used_block_dirty;
1194 const size_t fb_memsize = p->freeblks_lba_count * p->hd_sec_sz;
1195 if ( !p->freeblks && fb_memsize )
1196 {
1197 p->freeblks = wbfs_ioalloc(fb_memsize);
1198 dirty = true;
1199 }
1200
1201 if ( p->freeblks && dirty )
1202 {
1203 TRACE("WBFS: CALC FBT\n");
1204
1205 // fill complete array with zeros == mark all blocks as used
1206 wbfs_memset(p->freeblks,0,fb_memsize);
1207
1208 u32 idx = 0, mask = 0;
1209 u8 *ptr, *end = p->used_block + p->n_wbfs_sec;
1210 for ( ptr = p->used_block + 1; ptr < end; ptr++ )
1211 if (!*ptr)
1212 {
1213 const u32 bl = ptr - p->used_block - 1;
1214 const u32 new_idx = bl / 32;
1215 if ( idx != new_idx )
1216 {
1217 if ( idx >= p->freeblks_size4 )
1218 break; // end of free blocks table reached
1219 p->freeblks[idx] = htonl(mask);
1220 idx = new_idx;
1221 mask = 0;
1222 }
1223 mask |= (u32)1 << ( bl & 31 );
1224 }
1225 if ( idx < p->freeblks_size4 )
1226 p->freeblks[idx] = htonl(mask);
1227 }
1228
1229 return p->freeblks;
1230 }
1231
1232 ///////////////////////////////////////////////////////////////////////////////
1233
wbfs_calc_used_blocks(wbfs_t * p,bool force_reload,bool store_block0,wbfs_check_func func,void * param)1234 int wbfs_calc_used_blocks
1235 (
1236 wbfs_t * p, // valid WBFS descriptor
1237 bool force_reload, // true: definitely reload block #0
1238 bool store_block0, // true: don't free block0
1239 wbfs_check_func func, // call back function for errors
1240 void * param // user defined parameter
1241 )
1242 {
1243 DASSERT(p);
1244 char msg[100];
1245
1246 //------ setup
1247
1248 u8 * block0;
1249 if (p->block0)
1250 {
1251 block0 = p->block0;
1252 store_block0 = true;
1253 }
1254 else
1255 {
1256 block0 = wbfs_ioalloc(p->wbfs_sec_sz);
1257 force_reload = true;
1258 }
1259
1260 wbfs_setup_lists(p);
1261 u8 *used = p->used_block;
1262 DASSERT(used);
1263
1264 p->new_slot_err = p->all_slot_err = 0;
1265
1266
1267 //----- read block #0
1268
1269 if (force_reload)
1270 {
1271 TRACE("READ BLOCK0\n");
1272 int read_stat = p->read_hdsector( p->callback_data,
1273 p->part_lba,
1274 p->wbfs_sec_sz / p->hd_sec_sz,
1275 block0 );
1276 if (read_stat)
1277 {
1278 if (!store_block0)
1279 wbfs_iofree(block0);
1280 return read_stat;
1281 }
1282 }
1283
1284
1285 //----- scan free blocks table and mark free blocks with 0x80
1286
1287 const u8 FREE_MARK = 0x80;
1288
1289 u32 * fbt0 = (u32*)( block0 + ( p->part_lba + p->freeblks_lba ) * p->hd_sec_sz );
1290 u32 * fbt = fbt0;
1291 TRACE("block0=%p..%p, fbt=%p [%zx]\n",
1292 block0,block0+p->wbfs_sec_sz,fbt,(ccp)fbt-(ccp)block0);
1293 u8 * dest = used + 1;
1294 u32 i;
1295 for ( i = 0; i < p->freeblks_size4; i++ )
1296 {
1297 DASSERT( dest - used <= p->n_wbfs_sec );
1298 u32 v = wbfs_ntohl(*fbt++);
1299 noPRINT(" %05x,%08x -> %04zx\n",i,v,dest-used);
1300 if ( v == 0 )
1301 {
1302 // 32 used blocks
1303 dest += 32;
1304 }
1305 else if ( v == ~(u32)0 )
1306 {
1307 // 32 free blocks
1308 memset(dest,FREE_MARK,32);
1309 dest += 32;
1310 }
1311 else
1312 {
1313 u32 j;
1314 for ( j = 0; j < 32; j++, v >>= 1 )
1315 *dest++ = (v&1) ? FREE_MARK : 0x00;
1316 }
1317 }
1318 //HEXDUMP16(4,0,used,16);
1319 //HEXDUMP16(4,0x400,used+0x400,16);
1320
1321
1322 //----- scan discs, pass 1/2
1323
1324 const bool valid_slot_info = p->head->wbfs_version > 1;
1325 p->head->wbfs_version = WBFS_VERSION;
1326
1327 int slot;
1328 wbfs_disc_info_t * info = (wbfs_disc_info_t*)( block0 + p->hd_sec_sz );
1329
1330 for ( slot = 0; slot < p->max_disc; slot++ )
1331 {
1332 DASSERT( (u8*)info + p->disc_info_sz < block0 + p->wbfs_sec_sz );
1333 u8 slot_info = p->head->disc_table[slot]; // [dt]
1334 if (slot_info)
1335 {
1336 if (valid_slot_info)
1337 p->all_slot_err |= slot_info & ~WBFS_SLOT_VALID;
1338 else
1339 slot_info = WBFS_SLOT_VALID;
1340
1341 char * id6 = p->id_list[slot];
1342 memcpy(id6,info,6);
1343
1344 noPRINT("NEW WBFS INTERFACE: check slot %u: stat=%x, off=%zx, id=%s\n",
1345 slot, slot_info, (u8*)info - block0,
1346 wd_print_id(info,6,0) );
1347
1348 u16 * wlba_tab = info->wlba_table;
1349 int bl, bl_count = 0;
1350 for ( bl = 0; bl < p->n_wbfs_sec_per_disc; bl++ )
1351 {
1352 const u32 wlba = wbfs_ntohs(wlba_tab[bl]);
1353 if ( wlba >= p->n_wbfs_sec )
1354 {
1355 PRINT_IF(!func,"!!! NEW WBFS INTERFACE: invalid block %u.%u\n",slot,bl);
1356 slot_info = slot_info & ~WBFS_SLOT_VALID | WBFS_SLOT_INVALID;
1357 p->new_slot_err |= WBFS_SLOT_INVALID;
1358 if (func)
1359 {
1360 const uint msg_len = snprintf(msg,sizeof(msg),
1361 "Invalid WBFS block (%u>%u) at slot #%u [%s].",
1362 wlba, p->n_wbfs_sec-1, slot, id6 );
1363 func(p,WBFS_CHK_INVALID_BLOCK,slot,id6,wlba,0,msg,msg_len,param);
1364 }
1365 }
1366 else if ( wlba > 0 )
1367 {
1368 bl_count++;
1369
1370 if ( used[wlba] & FREE_MARK )
1371 {
1372 PRINT_IF(!func,
1373 "!!! NEW WBFS INTERFACE: slot %u.%x used free block #%x [%02x]\n",
1374 slot, bl, wlba, used[wlba] );
1375 slot_info |= WBFS_SLOT_F_FREED;
1376 p->new_slot_err |= WBFS_SLOT_F_FREED;
1377 if (func)
1378 {
1379 const uint msg_len = snprintf(msg,sizeof(msg),
1380 "WBFS block #%u marked free, but used by slot #%u [%s].",
1381 wlba, slot, id6 );
1382 func(p,WBFS_CHK_FREE_BLOCK_USED,slot,id6,wlba,0,msg,msg_len,param);
1383 }
1384 }
1385
1386 if ( ( used[wlba] & 0x7f ) < 0x7f )
1387 used[wlba]++;
1388 }
1389 }
1390
1391 if (!bl_count)
1392 {
1393 PRINT_IF(!func,
1394 "!!! NEW WBFS INTERFACE: disc @ slot %u does'n have any block\n",slot);
1395 slot_info |= WBFS_SLOT_INVALID;
1396 p->new_slot_err |= WBFS_SLOT_INVALID;
1397 }
1398
1399 p->head->disc_table[slot] = slot_info;
1400 }
1401 info = (wbfs_disc_info_t*)( (u8*)info + p->disc_info_sz );
1402 }
1403
1404
1405 //----- normalize 'used'
1406
1407 fbt = fbt0;
1408 u32 *fbt_end = fbt + p->freeblks_size4;
1409 memset(fbt,0,p->freeblks_size4*4);
1410 u32 v = 0;
1411 int count = 32;
1412 bool pass2_needed = false;
1413
1414 //HEXDUMP16(4,0,used,16);
1415 //HEXDUMP16(4,0x400,used+0x400,16);
1416
1417 for ( i = 1; i < p->n_wbfs_sec; i++ )
1418 {
1419 const u8 ucnt = used[i] & ~FREE_MARK;
1420 if (!ucnt)
1421 {
1422 v |= 1 << (i-1&31);
1423 if ( func && !used[i] )
1424 {
1425 const uint msg_len = snprintf(msg,sizeof(msg),
1426 "WBFS block #%u marked used, but is not used by any slot.",i);
1427 func(p,WBFS_CHK_UNUSED_BLOCK,-1,0,i,0,msg,msg_len,param);
1428 }
1429 }
1430 else if ( ucnt > 1 )
1431 {
1432 PRINT_IF(!func,
1433 "!!! NEW WBFS INTERFACE: block %u* used: #%x [%02x]\n", ucnt, i, used[i] );
1434 pass2_needed = true;
1435 if (func)
1436 {
1437 const uint msg_len = snprintf(msg,sizeof(msg),
1438 "WBFS block #%u used %u times.",i,ucnt);
1439 func(p,WBFS_CHK_MULTIUSED_BLOCK,-1,0,i,ucnt,msg,msg_len,param);
1440 }
1441 }
1442 used[i] = ucnt;
1443
1444 if ( !--count && fbt < fbt_end )
1445 {
1446 noPRINT("FBT[%04x] = %08x\n",4*(int)(fbt-fbt0),v);
1447 *fbt++ = wbfs_htonl(v);
1448 v = 0;
1449 count = 32;
1450 }
1451 }
1452
1453 if ( fbt < fbt_end )
1454 {
1455 noPRINT("FBT[%04x] = %08x [END]\n",4*(int)(fbt-fbt0),v);
1456 *fbt = wbfs_htonl(v);
1457 }
1458
1459 used[0] = 0xff;
1460 //HEXDUMP16(0,0,fbt0,p->freeblks_size4*4);
1461
1462
1463 //----- scan discs, pass 2/2
1464
1465 if ( pass2_needed )
1466 {
1467 info = (wbfs_disc_info_t*)( block0 + p->hd_sec_sz );
1468 for ( slot = 0; slot < p->max_disc; slot++ )
1469 {
1470 DASSERT( (u8*)info + p->disc_info_sz < block0 + p->wbfs_sec_sz );
1471 u8 slot_info = p->head->disc_table[slot];
1472 if (slot_info)
1473 {
1474 u16 * wlba_tab = info->wlba_table;
1475 int bl;
1476 for ( bl = 0; bl < p->n_wbfs_sec_per_disc; bl++ )
1477 {
1478 const u32 wlba = wbfs_ntohs(wlba_tab[bl]);
1479 if ( wlba > 0 && wlba < p->n_wbfs_sec && used[wlba] > 1 )
1480 {
1481 PRINT_IF(!func,
1482 "!!! NEW WBFS INTERFACE: slot %u.%x shares block #%x [%02x]\n",
1483 slot, bl, wlba, used[wlba] );
1484 slot_info |= WBFS_SLOT_F_SHARED;
1485 p->new_slot_err |= WBFS_SLOT_F_SHARED;
1486 if (func)
1487 {
1488 const uint msg_len = snprintf(msg,sizeof(msg),
1489 "Disc at slot #%u [%s] use shared block %u (used %u* total).",
1490 slot, p->id_list[slot], wlba, used[wlba] );
1491 func(p, WBFS_CHK_SHARED_BLOCK, slot, p->id_list[slot],
1492 bl, used[wlba], msg, msg_len, param );
1493 }
1494 }
1495 }
1496 }
1497 info = (wbfs_disc_info_t*)( (u8*)info + p->disc_info_sz );
1498 }
1499 }
1500
1501
1502 //----- terminate
1503
1504
1505 if (store_block0)
1506 {
1507 p->block0 = block0;
1508 wbfs_load_freeblocks(p);
1509 }
1510 else
1511 wbfs_iofree(block0);
1512
1513 p->all_slot_err |= p->new_slot_err;
1514 TRACE("SLOT-STAT: %02x/%02x\n",p->new_slot_err,p->all_slot_err);
1515 return 0;
1516 }
1517
1518 ///////////////////////////////////////////////////////////////////////////////
1519
wbfs_find_free_blocks(wbfs_t * p,u32 n_needed)1520 u32 wbfs_find_free_blocks
1521 (
1522 // returns index of first free block or WBFS_NO_BLOCK if not enough blocks free
1523
1524 wbfs_t * p, // valid WBFS descriptor
1525 u32 n_needed // number of needed blocks
1526 )
1527 {
1528 DASSERT(p);
1529 DASSERT(p->used_block);
1530 DASSERT(n_needed);
1531
1532 u8 *p1, *p2, *end = p->used_block + p->n_wbfs_sec;
1533 for ( p1 = p->used_block + 1; p1 < end && *p1; p1++ )
1534 ;
1535
1536 int count = n_needed;
1537 for ( p2 = p1; p2 < end; p2++ )
1538 if ( !*p2 && --count <= 0 )
1539 break;
1540
1541 if ( count > 0 )
1542 return WBFS_NO_BLOCK;
1543
1544 TRACE("found: %5zd..%5zd [%5zd]\n",p1-p->used_block,p2-p->used_block,p2-p1);
1545 u8 *found = p1;
1546 u32 range = p2 - p1;
1547
1548 while ( range >= n_needed )
1549 {
1550 for ( p1++; p1 < end && *p1; p1++ )
1551 ;
1552 for ( p2++; p2 < end && *p2; p2++ )
1553 ;
1554 if ( p2 >= end )
1555 break;
1556
1557 if ( p2 - p1 < range )
1558 {
1559 TRACE("found: %5zd..%5zd [%5zd]\n",p1-p->used_block,p2-p->used_block,p2-p1);
1560 found = p1;
1561 range = p2 - p1;
1562 }
1563 }
1564
1565 return found - p->used_block;
1566 }
1567
1568 ///////////////////////////////////////////////////////////////////////////////
1569
wbfs_get_free_block_count(wbfs_t * p)1570 u32 wbfs_get_free_block_count ( wbfs_t * p )
1571 {
1572 DASSERT(p);
1573 DASSERT(p->used_block);
1574
1575 u32 count = 0;
1576 u8 *ptr, *end = p->used_block + p->n_wbfs_sec;
1577 for ( ptr = p->used_block + 1; ptr < end; ptr++ )
1578 if (!*ptr)
1579 count++;
1580 return count;
1581 }
1582
1583 ///////////////////////////////////////////////////////////////////////////////
1584
wbfs_alloc_block(wbfs_t * p,u32 start_block)1585 u32 wbfs_alloc_block
1586 (
1587 wbfs_t * p, // valid WBFS descriptor
1588 u32 start_block // >0: start search at this block
1589 )
1590 {
1591 DASSERT(p);
1592 DASSERT(p->used_block);
1593
1594 if ( start_block < 1 || start_block >= p->n_wbfs_sec )
1595 start_block = 1;
1596
1597 u32 bl = start_block;
1598 do
1599 {
1600 if (!p->used_block[bl])
1601 {
1602 p->used_block[bl] = 1;
1603 p->used_block_dirty = p->is_dirty = true;
1604 noPRINT("wbfs_alloc_block(%p,%u) -> %d\n",p,start_block,bl);
1605 return bl;
1606 }
1607
1608 if ( ++bl >= p->n_wbfs_sec )
1609 bl = 1;
1610
1611 } while ( bl != start_block );
1612
1613 return WBFS_NO_BLOCK;
1614 }
1615
1616 ///////////////////////////////////////////////////////////////////////////////
1617
wbfs_find_last_used_block(wbfs_t * p)1618 u32 wbfs_find_last_used_block ( wbfs_t * p )
1619 {
1620 DASSERT(p);
1621 DASSERT(p->used_block);
1622 ASSERT( p->used_block[0] == 0xff );
1623
1624 u8 * ptr = p->used_block + p->n_wbfs_sec - 1;
1625 while (!*ptr)
1626 ptr--;
1627 return ptr - p->used_block;
1628 }
1629
1630 ///////////////////////////////////////////////////////////////////////////////
1631
wbfs_free_block(wbfs_t * p,u32 bl)1632 void wbfs_free_block ( wbfs_t *p, u32 bl )
1633 {
1634 DASSERT(p);
1635 DASSERT(p->used_block);
1636
1637 if ( bl > 0
1638 && bl < p->n_wbfs_sec
1639 && p->used_block[bl] > 0
1640 && p->used_block[bl] < 127
1641 )
1642 {
1643 if (!--p->used_block[bl])
1644 p->used_block_dirty = p->is_dirty = true;
1645 }
1646 }
1647
1648 ///////////////////////////////////////////////////////////////////////////////
1649
wbfs_use_block(wbfs_t * p,u32 bl)1650 void wbfs_use_block ( wbfs_t *p, u32 bl )
1651 {
1652 DASSERT(p);
1653 DASSERT(p->used_block);
1654
1655 if ( bl > 0 && bl < p->n_wbfs_sec && !p->used_block[bl] )
1656 {
1657 p->used_block[bl] = 1;
1658 p->used_block_dirty = p->is_dirty = true;
1659 }
1660 }
1661
1662 //
1663 ///////////////////////////////////////////////////////////////////////////////
1664
wbfs_add_disc(wbfs_t * p,wd_read_func_t read_src_wii_disc,void * callback_data,progress_callback_t spinner,const wd_select_t * psel,int copy_1_1)1665 u32 wbfs_add_disc
1666 (
1667 wbfs_t *p,
1668 wd_read_func_t read_src_wii_disc,
1669 void *callback_data,
1670 progress_callback_t spinner,
1671 const wd_select_t * psel,
1672 int copy_1_1
1673 )
1674 {
1675 wbfs_param_t par;
1676 memset(&par,0,sizeof(par));
1677
1678 par.read_src_wii_disc = read_src_wii_disc;
1679 par.callback_data = callback_data;
1680 par.spinner = spinner;
1681 par.psel = psel;
1682
1683 wd_select_t select_whole;
1684 if (copy_1_1)
1685 {
1686 wd_initialize_select(&select_whole);
1687 select_whole.whole_disc = true;
1688 par.psel = &select_whole;
1689 }
1690
1691 const u32 stat = wbfs_add_disc_param(p,&par);
1692 if (par.open_disc)
1693 wbfs_close_disc(par.open_disc);
1694 return stat;
1695 }
1696
1697 ///////////////////////////////////////////////////////////////////////////////
1698
wbfs_add_disc_param(wbfs_t * p,wbfs_param_t * par)1699 u32 wbfs_add_disc_param ( wbfs_t *p, wbfs_param_t * par )
1700 {
1701 ASSERT(p);
1702 ASSERT(par);
1703
1704 par->slot = -1; // no slot assigned
1705 par->open_disc = 0;
1706
1707 int i, slot;
1708 u32 wii_sec_per_wbfs_sect = 1 << (p->wbfs_sec_sz_s-p->wii_sec_sz_s);
1709 wbfs_disc_info_t *info = 0;
1710 u8* copy_buffer = 0;
1711 int disc_info_sz_lba;
1712 u8 * used = wbfs_malloc(WII_MAX_SECTORS);
1713
1714
1715 //----- open source disc
1716
1717 wd_disc_t * disc = wd_dup_disc(par->wd_disc);
1718 if (!disc)
1719 {
1720 disc = wd_open_disc( par->read_src_wii_disc,
1721 par->callback_data,
1722 par->iso_size,
1723 0,
1724 0,
1725 0 );
1726 if (!disc)
1727 WBFS_ERROR("unable to open wii disc");
1728 }
1729
1730 wd_filter_usage_table(disc,used,par->psel);
1731
1732 #if HAVE_PRINT0
1733 //wd_print_usage_tab(stdout,2,used,disc->iso_size,false);
1734 wd_print_usage_tab(stdout,2,used,WII_MAX_DISC_SIZE,false);
1735 #endif
1736
1737 //----- count total number of blocks to write
1738
1739 u32 current_block = 0;
1740 u32 total_blocks = 0;
1741
1742 for ( i = 0; i < p->n_wbfs_sec_per_disc; i++ )
1743 if ( wd_is_block_used(used, i, wii_sec_per_wbfs_sect) )
1744 total_blocks++;
1745
1746 PRINT("ADD, TOTAL BLOCKS= %u*%u*%u = %llu\n",
1747 total_blocks, wii_sec_per_wbfs_sect, WII_SECTOR_SIZE,
1748 (u64)total_blocks * wii_sec_per_wbfs_sect * WII_SECTOR_SIZE );
1749
1750 const u32 free_blocks = wbfs_get_free_block_count(p);
1751 if ( total_blocks > free_blocks )
1752 {
1753 wbfs_error("New discs needs %u wbfs blocks (%s)"
1754 " but only %u blocks are available.",
1755 total_blocks,
1756 wd_print_size(0,0,p->wbfs_sec_sz,false,WD_SIZE_AUTO),
1757 free_blocks );
1758 goto error;
1759 }
1760
1761 if (par->spinner)
1762 par->spinner(0,total_blocks,par->callback_data);
1763
1764 // [codeview]
1765
1766 for ( i = 0; i < p->max_disc; i++) // find a free slot.
1767 if (p->head->disc_table[i] == WBFS_SLOT_FREE)
1768 break;
1769
1770 if (i == p->max_disc)
1771 WBFS_ERROR("no space left on device (table full)");
1772
1773 p->head->disc_table[i] = WBFS_SLOT_VALID;
1774 slot = i;
1775
1776 // build disc info
1777 info = wbfs_ioalloc(p->disc_info_sz);
1778 memset(info,0,p->disc_info_sz);
1779 // [[2do]] use wd_read_and_patch()
1780 par->read_src_wii_disc(par->callback_data, 0, 0x100, info->dhead);
1781 if (par->wbfs_id6[0])
1782 memcpy(info->dhead,par->wbfs_id6,6);
1783
1784 copy_buffer = wbfs_ioalloc(p->wbfs_sec_sz);
1785 if (!copy_buffer)
1786 WBFS_ERROR("alloc memory");
1787
1788 #ifndef WIT // WIT does it in an other way (patching while reading)
1789 const u32 ptab_off = wd_get_ptab_sector(disc) * WII_SECTOR_SIZE;
1790 const int ptab_index = ptab_off >> p->wbfs_sec_sz_s;
1791 #endif
1792
1793 u32 bl = 0;
1794 if ( p->balloc_mode == WBFS_BA_AVOID_FRAG
1795 || p->balloc_mode == WBFS_BA_AUTO
1796 && p->hd_sec_sz * (u64)p->n_hd_sec >= 20*(u64)GiB )
1797 {
1798 bl = wbfs_find_free_blocks(p,total_blocks);
1799 TRACE("WBFS: AVOID FRAG, first block=%u\n",bl);
1800 }
1801
1802 for ( i = 0; i < p->n_wbfs_sec_per_disc; i++ )
1803 {
1804 info->wlba_table[i] = wbfs_htons(0);
1805 if ( wd_is_block_used(used, i, wii_sec_per_wbfs_sect))
1806 {
1807 bl = wbfs_alloc_block(p,bl);
1808 if ( bl == WBFS_NO_BLOCK )
1809 {
1810 // free disc slot
1811 p->head->disc_table[slot] = WBFS_SLOT_FREE;
1812
1813 // free already allocated blocks
1814 int j;
1815 for ( j = 0; j < i; j++ )
1816 {
1817 bl = wbfs_ntohs(info->wlba_table[j]);
1818 if (bl)
1819 wbfs_free_block(p,bl);
1820 }
1821 wbfs_sync(p);
1822 WBFS_ERROR("No space left on device (WBFS runs full)");
1823 }
1824 info->wlba_table[i] = wbfs_htons(bl);
1825
1826 u8 * dest = copy_buffer;
1827 const u32 wiimax = (i+1) * wii_sec_per_wbfs_sect;
1828 u32 subsec = 0;
1829 while ( subsec < wii_sec_per_wbfs_sect )
1830 {
1831 const u32 wiisec = i * wii_sec_per_wbfs_sect + subsec;
1832 if ( wiisec < WII_MAX_SECTORS && used[wiisec] )
1833 {
1834 u32 wiiend = wiisec+1;
1835 while ( wiiend < wiimax && used[wiiend] )
1836 wiiend++;
1837 const u32 size = ( wiiend - wiisec ) * p->wii_sec_sz;
1838 // [[2do]] use wd_read_and_patch()
1839 if (par->read_src_wii_disc(par->callback_data,
1840 wiisec * (p->wii_sec_sz>>2), size, dest ))
1841 WBFS_ERROR("error reading disc");
1842
1843 dest += size;
1844 subsec += wiiend - wiisec;
1845 }
1846 else
1847 {
1848 TRACE("LIBWBFS: FILL sec %u>%u -> %p\n",subsec,wiisec,dest);
1849 memset(dest,0,p->wii_sec_sz);
1850 dest += p->wii_sec_sz;
1851 subsec++;
1852 }
1853 }
1854
1855 #ifndef WIT // WIT does it in an other way (patching while reading)
1856 // fix the partition table.
1857 if ( i == ptab_index )
1858 wd_patch_ptab( disc,
1859 copy_buffer + ptab_off - i * p->wbfs_sec_sz,
1860 false );
1861 #endif
1862
1863 p->write_hdsector( p->callback_data,
1864 p->part_lba + bl * (p->wbfs_sec_sz / p->hd_sec_sz),
1865 p->wbfs_sec_sz / p->hd_sec_sz,
1866 copy_buffer );
1867
1868 if (par->spinner)
1869 par->spinner(++current_block,total_blocks,par->callback_data);
1870
1871 }
1872 }
1873
1874 // inode info
1875 par->iinfo.itime = 0ull;
1876 wbfs_setup_inode_info(p,&par->iinfo,1,1);
1877 memcpy( info->dhead + WBFS_INODE_INFO_OFF,
1878 &par->iinfo,
1879 sizeof(par->iinfo) );
1880
1881 // write disc info
1882 disc_info_sz_lba = p->disc_info_sz >> p->hd_sec_sz_s;
1883 p->write_hdsector( p->callback_data,
1884 p->part_lba + 1 + slot * disc_info_sz_lba,
1885 disc_info_sz_lba,
1886 info );
1887 if (p->id_list)
1888 memcpy(p->id_list[slot],info,sizeof(*p->id_list));
1889 wbfs_sync(p);
1890
1891 par->slot = slot;
1892 par->open_disc = wbfs_open_disc_by_info(p,slot,info,0);
1893 info = 0;
1894
1895 error:
1896 wd_close_disc(disc);
1897 if (used)
1898 wbfs_free(used);
1899 if (info)
1900 wbfs_iofree(info);
1901 if (copy_buffer)
1902 wbfs_iofree(copy_buffer);
1903
1904 return 0;
1905 }
1906
1907 ///////////////////////////////////////////////////////////////////////////////
1908
wbfs_add_phantom(wbfs_t * p,ccp phantom_id,u32 wii_sectors)1909 u32 wbfs_add_phantom ( wbfs_t *p, ccp phantom_id, u32 wii_sectors )
1910 {
1911 ASSERT(p);
1912 TRACE("LIBWBFS: +wbfs_add_phantom(%p,%s,%u)\n",
1913 p, phantom_id, wii_sectors );
1914
1915 if ( !phantom_id || !*phantom_id || !wii_sectors )
1916 return 1;
1917
1918 if ( wii_sectors > WII_MAX_SECTORS )
1919 wii_sectors = WII_MAX_SECTORS;
1920
1921 const u32 wii_sec_per_wbfs_sect = 1 << (p->wbfs_sec_sz_s-p->wii_sec_sz_s);
1922 wbfs_disc_info_t * info = 0;
1923
1924 // find a free slot.
1925 int slot;
1926 for ( slot = 0; slot < p->max_disc; slot++ )
1927 if (!p->head->disc_table[slot])
1928 break;
1929
1930 u32 err = 0;
1931 if ( slot == p->max_disc )
1932 {
1933 err++;
1934 WBFS_ERROR("no space left on device (table full)");
1935 }
1936
1937 p->head->disc_table[slot] = WBFS_SLOT_VALID;
1938
1939 // build disc info
1940 info = wbfs_ioalloc(p->disc_info_sz);
1941 memset(info,0,p->disc_info_sz);
1942 memcpy(info->dhead,phantom_id,6);
1943 snprintf( (char*)info->dhead + WII_TITLE_OFF,
1944 WII_TITLE_SIZE, "Phantom %.6s @ slot %u -> not a real disc, for tests only!",
1945 phantom_id, slot );
1946
1947 const u32 max_wbfs_sect = (wii_sectors-1) / wii_sec_per_wbfs_sect + 1;
1948 TRACE(" - add %u wbfs sectors to slot %u\n",max_wbfs_sect,slot);
1949
1950 u32 bl = 0;
1951 if ( p->balloc_mode == WBFS_BA_AVOID_FRAG
1952 || p->balloc_mode == WBFS_BA_AUTO
1953 && p->hd_sec_sz * (u64)p->n_hd_sec >= 20*(u64)GiB )
1954 {
1955 bl = wbfs_find_free_blocks(p,max_wbfs_sect);
1956 TRACE("WBFS: AVOID FRAG, first block=%u\n",bl);
1957 }
1958
1959 int i;
1960 for ( i = 0; i < max_wbfs_sect; i++)
1961 {
1962 bl = wbfs_alloc_block(p,bl);
1963 if ( bl == WBFS_NO_BLOCK )
1964 {
1965 if (!i)
1966 p->head->disc_table[slot] = WBFS_SLOT_FREE;
1967 err++;
1968 break; // use smaller phantom
1969 }
1970
1971 if ( i == 0 )
1972 p->write_hdsector( p->callback_data,
1973 p->part_lba + bl * (p->wbfs_sec_sz / p->hd_sec_sz),
1974 1,
1975 info );
1976
1977 info->wlba_table[i] = wbfs_htons(bl);
1978 }
1979
1980 // setup inode info
1981 wbfs_inode_info_t * iinfo = wbfs_get_inode_info(p,info,2);
1982 wbfs_setup_inode_info(p,iinfo,1,1);
1983
1984 // write disc info
1985 *(u32*)(info->dhead+24) = wbfs_ntohl(0x5D1C9EA3);
1986 u32 disc_info_sz_lba = p->disc_info_sz >> p->hd_sec_sz_s;
1987 p->write_hdsector( p->callback_data,
1988 p->part_lba + 1 + slot * disc_info_sz_lba,
1989 disc_info_sz_lba,
1990 info );
1991
1992 if (p->id_list)
1993 memcpy(p->id_list[slot],info,sizeof(*p->id_list));
1994 wbfs_sync(p);
1995
1996 error:
1997 if (info)
1998 wbfs_iofree(info);
1999 TRACE("LIBWBFS: -wbfs_add_phantom() return %u\n",err);
2000 return err;
2001 }
2002
2003 ///////////////////////////////////////////////////////////////////////////////
2004
wbfs_rm_disc(wbfs_t * p,u8 * discid,int slot,int free_slot_only)2005 u32 wbfs_rm_disc
2006 (
2007 wbfs_t * p, // valid WBFS descriptor
2008 u8 * discid, // id6 to remove. If NULL: remove 'slot'
2009 int slot, // slot index, only used if 'discid==NULL'
2010 int free_slot_only // true: do not free blocks
2011 )
2012 {
2013 TRACE("LIBWBFS: +wbfs_rm_disc(%p,%.6s,%d,%d)\n",
2014 p, discid ? (ccp)discid : "-", slot, free_slot_only );
2015 DASSERT(p);
2016 DASSERT(p->head);
2017
2018 wbfs_disc_t *d = discid
2019 ? wbfs_open_disc_by_id6(p,discid)
2020 : wbfs_open_disc_by_slot(p,slot,false);
2021 if (!d)
2022 return 1;
2023 slot = d->slot;
2024
2025 TRACE("LIBWBFS: disc_table[slot=%d]=%x\n", slot, p->head->disc_table[slot] );
2026
2027 if (!free_slot_only)
2028 {
2029 int i;
2030 for ( i=0; i< p->n_wbfs_sec_per_disc; i++)
2031 {
2032 u16 iwlba = wbfs_ntohs(d->header->wlba_table[i]);
2033 //TRACE("FREE %u\n",iwlba);
2034 if (iwlba)
2035 wbfs_free_block(p,iwlba);
2036 }
2037
2038 wbfs_inode_info_t * iinfo = wbfs_get_disc_inode_info(d,1);
2039 ASSERT(iinfo);
2040 wbfs_setup_inode_info(p,iinfo,0,1);
2041 #ifdef TEST
2042 *(u32*)(d->header->dhead+WII_MAGIC_OFF) = wbfs_htonl(WII_MAGIC_DELETED);
2043 #endif
2044 const u32 disc_info_sz_lba = p->disc_info_sz >> p->hd_sec_sz_s;
2045 p->write_hdsector(
2046 p->callback_data,
2047 p->part_lba + 1 + slot * disc_info_sz_lba,
2048 disc_info_sz_lba,
2049 d->header );
2050 }
2051 wbfs_close_disc(d);
2052
2053 p->head->disc_table[slot] = WBFS_SLOT_FREE;
2054 if (p->id_list)
2055 memset(p->id_list[slot],0,sizeof(*p->id_list));
2056 wbfs_sync(p);
2057
2058 TRACE("LIBWBFS: -wbfs_rm_disc() return=0\n");
2059 return 0;
2060 }
2061
2062 ///////////////////////////////////////////////////////////////////////////////
2063
wbfs_trim(wbfs_t * p)2064 u32 wbfs_trim ( wbfs_t * p ) // trim the file-system to its minimum size
2065 {
2066 DASSERT(p);
2067 DASSERT(p->used_block);
2068 DASSERT( p->wbfs_sec_sz_s >= p->hd_sec_sz_s );
2069
2070 const u32 max_block = wbfs_find_last_used_block(p) + 1;
2071 wbfs_calc_geometry( p, max_block << p->wbfs_sec_sz_s - p->hd_sec_sz_s,
2072 p->hd_sec_sz, p->wbfs_sec_sz );
2073 p->used_block_dirty = p->is_dirty = true;
2074 wbfs_sync(p);
2075
2076 // os layer will truncate the file.
2077 TRACE("LIBWBFS: -wbfs_trim() return=%u\n",max_block);
2078 return max_block;
2079 }
2080
2081 //
2082 ///////////////////////////////////////////////////////////////////////////////
2083 /////////////// END ///////////////
2084 ///////////////////////////////////////////////////////////////////////////////
2085
2086