source: ps2launchargs/source/uLaunchELF/vmcfs/src/vmc_misc.c@ 1103

Last change on this file since 1103 was 1101, checked in by iritscen, 7 years ago

Added following to ps2launchargs:\n-Source code.\n-DLL needed to run ps2client.\n-Instructions for building uLaunchELF.

  • Property svn:executable set to *
File size: 27.8 KB
Line 
1#include "vmc.h"
2
3
4// Misc fonctions
5
6//----------------------------------------------------------------------------
7// Search a direntry corresponding to a path
8//----------------------------------------------------------------------------
9unsigned int getDirentryFromPath ( struct direntry* retval, const char* path, struct gen_privdata* gendata, int unit )
10{
11
12 PROF_START ( getDirentryFromPathProf );
13
14 DEBUGPRINT ( 6, "vmcfs: Searching Direntry corresponding to path: %s\n", path );
15
16 // Skip past the first slash if they opened a file such as
17 // vmc0: / file.txt ( which means the path passed here will be / file.txt, we
18 // want to skip that first slash, to ease comparisons.
19 int pathoffset = 0;
20
21 if ( path[ 0 ] == '/' )
22 pathoffset = 1;
23
24 if ( ( path[ 0 ] == '/' || path[ 0 ] == '.' ) && path[ 1 ] == '\0' ) // rootdirectory
25 {
26
27 gendata->dirent_page = 0;
28 readPage ( gendata->fd, ( unsigned char* ) retval, gendata->first_allocatable * g_Vmc_Image[ unit ].header.pages_per_cluster );
29
30 PROF_END ( getDirentryFromPathProf );
31
32 return ROOT_CLUSTER;
33
34 }
35
36 struct direntry dirent; // Our temporary directory entry
37
38 int status = 0; // The status of our search, if 0 at the end, we didn't find path
39 unsigned int current_cluster = 0; // The cluster we are currently scanning for directory entries
40 int length = 1; // The number of items in the current directory
41 int i = 0;
42
43 // Our main loop that goes through files / folder searching for the right one
44 for ( i = 0; i < length; i++ )
45 {
46
47 gendata->dirent_page = i % g_Vmc_Image[ unit ].header.pages_per_cluster;
48
49 DEBUGPRINT ( 6, "vmcfs: Reading in allocatable cluster %u / page %u\n", ( current_cluster + gendata->first_allocatable ), ( current_cluster + gendata->first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster + gendata->dirent_page );
50
51 // Reads either the first or second page of a cluster, depending
52 // on the value currently stored in i
53 readPage ( gendata->fd, ( unsigned char* ) &dirent, ( current_cluster + gendata->first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster + gendata->dirent_page );
54
55 // Check if this was the first entry ( aka the rootdirectory )
56 if ( i == 0 && current_cluster == 0 )
57 length = dirent.length;
58
59 DEBUGPRINT ( 5, "vmcfs: Direntry Informations\n" );
60 DEBUGPRINT ( 5, "vmcfs: Object Type : %s\n", ( dirent.mode & DF_DIRECTORY ) ?"Folder":"File" );
61 DEBUGPRINT ( 5, "vmcfs: Object Name : %s\n", dirent.name );
62 DEBUGPRINT ( 5, "vmcfs: Object Exists : %s\n", ( dirent.mode & DF_EXISTS ) ?"Yes":"No" );
63 DEBUGPRINT ( 5, "vmcfs: Object Length : %u\n", dirent.length );
64 DEBUGPRINT ( 5, "vmcfs: Object Cluster : %u\n", dirent.cluster );
65
66 // Now that we have a pages worth of data, check if it is the
67 // Directory we are searching for.
68
69 if ( memcmp ( dirent.name, path + pathoffset, strlen ( dirent.name ) ) == 0 )
70 {
71
72 // Increase the path offset by the length of the directory
73 pathoffset += strlen ( dirent.name );
74
75 // If the next item in the pathname is the null terminator,
76 // we must be at the end of the path string, and that means
77 // we found the correct entry, so we can break.
78 if ( path[ pathoffset ] == '\0' || ( path[ pathoffset ] == '/' && path[ pathoffset + 1 ] == '\0' ) )
79 {
80
81 DEBUGPRINT ( 6, "vmcfs: Breaking from function\n" );
82 DEBUGPRINT ( 6, "vmcfs: dir_cluster = %u\n", dirent.cluster );
83 DEBUGPRINT ( 6, "vmcfs: dirent.name = %s\n", dirent.name );
84 DEBUGPRINT ( 6, "vmcfs: dirent.length = %u\n", dirent.length );
85
86 status = 1;
87
88 break;
89
90 }
91 // Otherwise we found the subfolder, but not the
92 // requested entry, keep going
93 else
94 {
95
96 DEBUGPRINT ( 6, "vmcfs: Recursing into subfolder\n" );
97 DEBUGPRINT ( 6, "vmcfs: dir_cluster = %u\n", dirent.cluster );
98 DEBUGPRINT ( 6, "vmcfs: dirent.name = %s\n", dirent.name );
99 DEBUGPRINT ( 6, "vmcfs: dirent.length = %u\n", dirent.length );
100
101 i = -1; // will be 0 when we continue, essentially starting the loop over again
102 current_cluster = dirent.cluster; // dirent.cluster refer to fat table and current_cluster to allocatable place
103 length = dirent.length; // set length to current directory length
104 pathoffset++; // add one to skip past the / in the folder name
105
106 continue;
107
108 }
109
110 }
111
112 // If we just read the second half of a cluster, we need to set
113 // current_cluster to the next cluster in the chain.
114 if ( i % g_Vmc_Image[ unit ].header.pages_per_cluster )
115 {
116
117 current_cluster = getFatEntry ( gendata->fd, current_cluster, gendata->indir_fat_clusters, FAT_VALUE );
118
119 }
120
121 }
122
123 // When we get here, that means one of two things:
124 // 1 ) We found the requested folder / file
125 // 2 ) We searched through all files / folders, and could not find it.
126 // To determine which one it was, check the status variable.
127 if ( status == 0 )
128 {
129
130 PROF_END ( getDirentryFromPathProf )
131
132 return NOFOUND_CLUSTER;
133
134 }
135
136 // Copy the last directory entry's contents into 'retval'
137 memcpy ( retval, &dirent, sizeof ( dirent ) );
138
139 PROF_END ( getDirentryFromPathProf )
140
141 // Return the cluster where the desired directory entry can be found
142 return current_cluster;
143
144}
145
146
147//----------------------------------------------------------------------------
148// Add 2 pseudo entries for a new directory
149//----------------------------------------------------------------------------
150unsigned int addPseudoEntries ( struct gen_privdata* gendata, struct direntry* parent, int unit )
151{
152
153 // Get a free cluster we can use to store the entries '.' and '..'
154 unsigned int pseudo_entries_cluster = getFreeCluster ( gendata, unit );
155
156 if ( pseudo_entries_cluster == ERROR_CLUSTER )
157 {
158
159 DEBUGPRINT ( 2, "vmcfs: Not enough free space to add pseudo entries. Aborting.\n" );
160
161 return ERROR_CLUSTER;
162
163 }
164
165 // Create the first 2 psuedo entries for the folder, and write them
166 DEBUGPRINT ( 5, "vmcfs: Adding pseudo entries into fat table cluster %u\n", pseudo_entries_cluster );
167
168 struct direntry pseudo_entries;
169
170 memset ( &pseudo_entries, 0, sizeof ( pseudo_entries ) );
171
172 // fill pseudo entries
173 strcpy ( pseudo_entries.name, "." );
174 pseudo_entries.dir_entry = parent->length;
175 pseudo_entries.length = 0;
176 pseudo_entries.cluster = parent->cluster;
177 pseudo_entries.mode = DF_EXISTS | DF_0400 | DF_DIRECTORY | DF_READ | DF_WRITE | DF_EXECUTE; // 0x8427
178
179 getPs2Time ( &pseudo_entries.created );
180 getPs2Time ( &pseudo_entries.modified );
181
182 // write first pseudo entry
183 writePage ( gendata->fd, ( unsigned char* ) &pseudo_entries, ( pseudo_entries_cluster + gendata->first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster );
184
185 strcpy ( pseudo_entries.name, ".." );
186 pseudo_entries.dir_entry = 0;
187 pseudo_entries.cluster = 0;
188
189 // write second pseudo entry
190 writePage ( gendata->fd, ( unsigned char* ) &pseudo_entries, ( pseudo_entries_cluster + gendata->first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster + 1 );
191
192 // set cluster as EOF
193 setFatEntry ( gendata->fd, pseudo_entries_cluster, EOF_CLUSTER, gendata->indir_fat_clusters, FAT_SET );
194
195 return pseudo_entries_cluster;
196
197}
198
199
200//----------------------------------------------------------------------------
201// Add an object into vmc image.
202// This fonction get a free cluster where it can insert the object, insert it and return the cluster number.
203// Object can be a file or a folder.
204//----------------------------------------------------------------------------
205unsigned int addObject ( struct gen_privdata* gendata, unsigned int parent_cluster, struct direntry* parent, struct direntry* dirent, int unit )
206{
207
208 int i = 0;
209 unsigned int retval = ERROR_CLUSTER;
210 unsigned int current_cluster = parent->cluster;
211
212 // Find to the last cluster in the list of files / folder to add our new object after it
213 for ( i = 0; i < parent->length; i += g_Vmc_Image[ unit ].header.pages_per_cluster )
214 {
215
216 DEBUGPRINT ( 6, "vmcfs: Following fat table cluster: %u\n", current_cluster );
217
218 if ( getFatEntry ( gendata->fd, current_cluster, gendata->indir_fat_clusters, FAT_VALUE ) == EOF_CLUSTER )
219 {
220
221 DEBUGPRINT ( 6, "vmcfs: Last used cluster in fat table %u\n", current_cluster );
222 break;
223
224 }
225
226 current_cluster = getFatEntry ( gendata->fd, current_cluster, gendata->indir_fat_clusters, FAT_VALUE );
227
228 }
229
230 // Check if we need a new cluster or if we can add our object at the end of an allocatable cluster
231 if ( parent->length % g_Vmc_Image[ unit ].header.pages_per_cluster == 0 ) // if its even, we need a new cluster for our file
232 {
233
234 // Get a free cluster because our object require an additional cluster
235 unsigned int nextfree_cluster = getFreeCluster ( gendata, unit );
236
237 if ( nextfree_cluster == ERROR_CLUSTER )
238 {
239
240 DEBUGPRINT ( 2, "vmcfs: Not enough free space. Aborting.\n" );
241
242 return ERROR_CLUSTER;
243
244 }
245
246 DEBUGPRINT ( 6, "vmcfs: Added new object in fat table cluster %u ( Page %u ) \n", current_cluster, current_cluster * g_Vmc_Image[ unit ].header.pages_per_cluster );
247
248 setFatEntry ( gendata->fd, current_cluster, nextfree_cluster, gendata->indir_fat_clusters, FAT_SET ); // update the last cluster in the directory entry list to point to our new cluster
249 setFatEntry ( gendata->fd, nextfree_cluster, EOF_CLUSTER, gendata->indir_fat_clusters, FAT_SET ); // set the free cluster we just found to be EOF
250
251 // If the object is a folder, we have to add 2 psuedoentries
252 if ( dirent->mode & DF_DIRECTORY )
253 {
254
255 // Link the new folder to the entries we just created
256 dirent->cluster = addPseudoEntries( gendata, parent, unit );
257
258 if ( dirent->cluster == ERROR_CLUSTER )
259 return ERROR_CLUSTER;
260
261 // Set the length of the directory to 2, for the 2 psuedoentries we just added
262 dirent->length = 2;
263
264 }
265
266 // write the page containing our direntry object information
267 writePage ( gendata->fd, ( unsigned char* ) dirent, ( nextfree_cluster + gendata->first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster );
268
269 // now we need to update the length of the parent directory
270 parent->length++;
271 writePage ( gendata->fd, ( unsigned char* ) parent, ( parent_cluster + gendata->first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster + gendata->dirent_page );
272
273 gendata->dirent_page = 0;
274 retval = nextfree_cluster;
275
276 }
277 else // otherwise we can just add the directory entry to the end of the last cluster
278 {
279
280 DEBUGPRINT ( 5, "vmcfs: Added new object in fat table cluster %u ( Page %u ) \n", current_cluster, current_cluster * g_Vmc_Image[ unit ].header.pages_per_cluster + 1 );
281
282 // If the object is a folder, we have to add 2 psuedoentries
283 if ( dirent->mode & DF_DIRECTORY )
284 {
285
286 // Link the new folder to the entries we just created
287 dirent->cluster = addPseudoEntries( gendata, parent, unit );
288
289 if ( dirent->cluster == ERROR_CLUSTER )
290 return ERROR_CLUSTER;
291
292 // Set the length of the directory to 2, for the 2 psuedoentries we just added
293 dirent->length = 2;
294
295 }
296
297 // write the page containing our direntry object information
298 writePage ( gendata->fd, ( unsigned char* ) dirent, ( current_cluster + gendata->first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster + 1 );// write the page containing our directory information ( + 1 because we are writing the second page in the cluster )
299
300 // now we need to update the length of the parent directory
301 parent->length++;
302 writePage ( gendata->fd, ( unsigned char* ) parent, ( parent_cluster + gendata->first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster + gendata->dirent_page );
303
304 gendata->dirent_page = 1;
305 retval = current_cluster;
306
307 }
308
309 return retval;
310
311}
312
313
314//----------------------------------------------------------------------------
315// Remove an object from vmc image.
316// Object can be a file or a directory.
317// Follow fat table to find the last cluster of the direntry chain cluster. ( EOF_CLUSTER )
318// Change bit mask of tested cluster if it's not EOF. ( only for files )
319// Set as free the last cluster of the direntry.
320// Finaly, set deleted flag of the direntry. ( DF_EXISTS flag )
321//----------------------------------------------------------------------------
322void removeObject ( struct gen_privdata* gendata, unsigned int dirent_cluster, struct direntry* dirent, int unit )
323{
324
325 unsigned int current_cluster = 0;
326 unsigned int last_cluster = dirent->cluster;
327
328 DEBUGPRINT ( 3, "vmcfs: Searching last cluster of direntry\n" );
329
330 while ( 1 )
331 {
332
333 current_cluster = getFatEntry ( gendata->fd, last_cluster, gendata->indir_fat_clusters, FAT_VALUE );
334
335 if ( current_cluster == FREE_CLUSTER )
336 {
337
338 // FREE_CLUSTER mean nothing to remove or error, so return
339 DEBUGPRINT ( 10, "vmcfs: Testing cluster %u ... value is FREE_CLUSTER\n", last_cluster );
340
341 return;
342
343 }
344 else if ( current_cluster == EOF_CLUSTER )
345 {
346
347 // EOF_CLUSTER mean last cluster of the direntry is found
348 DEBUGPRINT ( 3, "vmcfs: Last cluster of direntry at %u\n", last_cluster );
349
350 break;
351
352 }
353 else
354 {
355
356 // Otherwise change bit mask of tested cluster
357 DEBUGPRINT ( 10, "vmcfs: Testing cluster %u ... value is %u\n", last_cluster, current_cluster );
358
359 setFatEntry ( gendata->fd, last_cluster, current_cluster, gendata->indir_fat_clusters, FAT_RESET );
360
361 }
362
363 last_cluster = current_cluster;
364
365 }
366
367 // Set last cluster of direntry as free.
368 setFatEntry ( gendata->fd, last_cluster, FREE_CLUSTER, gendata->indir_fat_clusters, FAT_RESET ); // set the last cluster of the file as free
369
370 // Set object as deleted. ( Remove DF_EXISTS flag )
371 dirent->mode = dirent->mode ^ DF_EXISTS;
372 writePage ( gendata->fd, ( unsigned char* ) dirent, ( dirent_cluster + gendata->first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster + gendata->dirent_page );
373
374}
375
376
377//----------------------------------------------------------------------------
378// Return a free cluster.
379//----------------------------------------------------------------------------
380unsigned int getFreeCluster ( struct gen_privdata* gendata, int unit )
381{
382
383 unsigned int i = 0;
384 unsigned int value = 0;
385 unsigned int cluster_mask = MASK_CLUSTER;
386
387 for ( i = g_Vmc_Image[ unit ].last_free_cluster; i < gendata->last_allocatable; i++ )
388 {
389
390 value = getFatEntry ( gendata->fd, i - gendata->first_allocatable, gendata->indir_fat_clusters, FAT_VALUE );
391
392 if ( value == FREE_CLUSTER )
393 {
394
395 DEBUGPRINT ( 10, "vmcfs: Testing fat table cluster %d ... value is FREE_CLUSTER\n", i - gendata->first_allocatable );
396
397 DEBUGPRINT ( 6, "vmcfs: Free cluster found at %d in fat table\n", i - gendata->first_allocatable );
398 g_Vmc_Image[ unit ].last_free_cluster = i;
399
400 return ( i - gendata->first_allocatable );
401
402 }
403 else if ( value == EOF_CLUSTER )
404 {
405
406 DEBUGPRINT ( 10, "vmcfs: Testing fat table cluster %d ... value is EOF_CLUSTER\n", i - gendata->first_allocatable );
407
408 }
409 else
410 {
411
412 DEBUGPRINT ( 10, "vmcfs: Testing fat table cluster %d ... value is %d\n", i - gendata->first_allocatable, value );
413
414 cluster_mask = getFatEntry ( gendata->fd, i - gendata->first_allocatable, gendata->indir_fat_clusters, FAT_MASK );
415
416 if ( cluster_mask != MASK_CLUSTER )
417 {
418
419 DEBUGPRINT ( 6, "vmcfs: Free cluster found at %d in fat table\n", i - gendata->first_allocatable );
420 g_Vmc_Image[ unit ].last_free_cluster = i;
421
422 return ( i - gendata->first_allocatable );
423
424 }
425
426 }
427
428 }
429
430 return ERROR_CLUSTER;
431
432}
433
434
435//----------------------------------------------------------------------------
436// Set default specification to superblock header when card is not formated
437//----------------------------------------------------------------------------
438int setDefaultSpec ( int unit )
439{
440
441 DEBUGPRINT ( 4, "vmcfs: SuperBlock set by default\n" );
442
443 memset ( &g_Vmc_Image[ unit ].header, g_Vmc_Image[ unit ].erase_byte, sizeof ( struct superblock ) );
444
445 strcpy ( g_Vmc_Image[ unit ].header.magic, "Sony PS2 Memory Card Format 1.2.0.0" );
446
447 DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: magic[40] : %s\n" , g_Vmc_Image[ unit ].header.magic );
448
449 g_Vmc_Image[ unit ].header.page_size = 0x200;
450 g_Vmc_Image[ unit ].header.pages_per_cluster = 0x2;
451 g_Vmc_Image[ unit ].header.pages_per_block = 0x10;
452 g_Vmc_Image[ unit ].header.unused0 = 0xFF00;
453
454 g_Vmc_Image[ unit ].cluster_size = g_Vmc_Image[ unit ].header.page_size * g_Vmc_Image[ unit ].header.pages_per_cluster;
455 g_Vmc_Image[ unit ].erase_byte = 0xFF;
456 g_Vmc_Image[ unit ].last_idc = EOF_CLUSTER;
457 g_Vmc_Image[ unit ].last_cluster = EOF_CLUSTER;
458
459 if ( g_Vmc_Image[ unit ].card_size %( g_Vmc_Image[ unit ].header.page_size + 0x10 ) == 0 )
460 {
461
462 g_Vmc_Image[ unit ].ecc_flag = TRUE;
463 g_Vmc_Image[ unit ].total_pages = g_Vmc_Image[ unit ].card_size / ( g_Vmc_Image[ unit ].header.page_size + 0x10 );
464 g_Vmc_Image[ unit ].header.clusters_per_card = g_Vmc_Image[ unit ].card_size / ( ( g_Vmc_Image[ unit ].header.page_size + 0x10 ) * g_Vmc_Image[ unit ].header.pages_per_cluster );
465
466 }
467 else if ( g_Vmc_Image[ unit ].card_size %g_Vmc_Image[ unit ].header.page_size == 0 )
468 {
469
470 g_Vmc_Image[ unit ].ecc_flag = FALSE;
471 g_Vmc_Image[ unit ].total_pages = g_Vmc_Image[ unit ].card_size / g_Vmc_Image[ unit ].header.page_size;
472 g_Vmc_Image[ unit ].header.clusters_per_card = g_Vmc_Image[ unit ].card_size / ( g_Vmc_Image[ unit ].header.page_size * g_Vmc_Image[ unit ].header.pages_per_cluster );
473
474 }
475 else
476 {
477
478 // Size error
479 return 0;
480
481 }
482
483 g_Vmc_Image[ unit ].header.mc_type = 0x2;
484 g_Vmc_Image[ unit ].header.mc_flag = 0x2B;
485
486 DEBUGPRINT ( 4, "vmcfs: Image file Info: Number of pages : %d\n", g_Vmc_Image[ unit ].total_pages );
487 DEBUGPRINT ( 4, "vmcfs: Image file Info: Size of a cluster : %d bytes\n", g_Vmc_Image[ unit ].cluster_size );
488 DEBUGPRINT ( 4, "vmcfs: Image file Info: ECC shunk found : %s\n", g_Vmc_Image[ unit ].ecc_flag ? "YES" : "NO" );
489 DEBUGPRINT ( 3, "vmcfs: Image file Info: Vmc card type : %s MemoryCard.\n", ( g_Vmc_Image[ unit ].header.mc_type == PSX_MEMORYCARD ? "PSX" : ( g_Vmc_Image[ unit ].header.mc_type == PS2_MEMORYCARD ? "PS2" : "PDA" ) ) );
490 DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: page_size : 0x%02x\n", g_Vmc_Image[ unit ].header.page_size );
491 DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: pages_per_cluster : 0x%02x\n", g_Vmc_Image[ unit ].header.pages_per_cluster );
492 DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: pages_per_block : 0x%02x\n", g_Vmc_Image[ unit ].header.pages_per_block );
493 DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: clusters_per_card : 0x%02x\n", g_Vmc_Image[ unit ].header.clusters_per_card );
494
495 g_Vmc_Image[ unit ].header.first_allocatable = ( ( ( ( g_Vmc_Image[ unit ].total_pages - 1 ) * ( g_Vmc_Image[ unit ].cluster_size / g_Vmc_Image[ unit ].header.page_size ) ) / g_Vmc_Image[ unit ].cluster_size ) + 1 ) + 8 + ( ( g_Vmc_Image[ unit ].total_pages - 1 ) / ( g_Vmc_Image[ unit ].total_pages * g_Vmc_Image[ unit ].header.pages_per_cluster * ( g_Vmc_Image[ unit ].cluster_size / g_Vmc_Image[ unit ].header.page_size ) ) ) + 1;
496 g_Vmc_Image[ unit ].header.last_allocatable = ( g_Vmc_Image[ unit ].header.clusters_per_card - g_Vmc_Image[ unit ].header.first_allocatable ) - ( ( g_Vmc_Image[ unit ].header.pages_per_block / g_Vmc_Image[ unit ].header.pages_per_cluster ) * g_Vmc_Image[ unit ].header.pages_per_cluster );
497 g_Vmc_Image[ unit ].header.root_cluster = 0;
498
499 g_Vmc_Image[ unit ].header.backup_block1 = ( g_Vmc_Image[ unit ].total_pages / g_Vmc_Image[ unit ].header.pages_per_block ) - 1;
500 g_Vmc_Image[ unit ].header.backup_block2 = g_Vmc_Image[ unit ].header.backup_block1 - 1;
501 memset ( g_Vmc_Image[ unit ].header.unused1, g_Vmc_Image[ unit ].erase_byte, 8 );
502
503 DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: first_allocatable : 0x%02x\n", g_Vmc_Image[ unit ].header.first_allocatable );
504 DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: last_allocatable : 0x%02x\n", g_Vmc_Image[ unit ].header.last_allocatable );
505 DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: root_cluster : 0x%02x\n", g_Vmc_Image[ unit ].header.root_cluster );
506 DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: backup_block1 : 0x%02x\n", g_Vmc_Image[ unit ].header.backup_block1 );
507 DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: backup_block2 : 0x%02x\n", g_Vmc_Image[ unit ].header.backup_block2 );
508
509 unsigned int last_blk_sector = 8;
510 int i = 0;
511
512 for ( i = 0; i <= ( ( g_Vmc_Image[ unit ].total_pages - 1 ) / 65536 ); i++ )
513 {
514 if ( ( ( ( last_blk_sector + i ) * ( g_Vmc_Image[ unit ].cluster_size / g_Vmc_Image[ unit ].header.page_size ) ) %g_Vmc_Image[ unit ].header.pages_per_block ) == 0 )
515 {
516 last_blk_sector = last_blk_sector + i;
517 }
518 g_Vmc_Image[ unit ].header.indir_fat_clusters[ i ]= last_blk_sector + i;
519 }
520
521 for ( i = 0; g_Vmc_Image[ unit ].header.indir_fat_clusters[ i ]!= 0; i++ )
522 DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: indir_fat_clusters[%d] : 0x%02x\n", i, g_Vmc_Image[ unit ].header.indir_fat_clusters[ i ]);
523
524 memset ( g_Vmc_Image[ unit ].header.bad_block_list, g_Vmc_Image[ unit ].erase_byte, sizeof ( unsigned int ) * 32 );
525
526 g_Vmc_Image[ unit ].header.unused2 = 0;
527 g_Vmc_Image[ unit ].header.unused3 = 0x100;
528 g_Vmc_Image[ unit ].header.size_in_megs = ( g_Vmc_Image[ unit ].total_pages * g_Vmc_Image[ unit ].header.page_size ) / ( g_Vmc_Image[ unit ].cluster_size * g_Vmc_Image[ unit ].cluster_size );
529 g_Vmc_Image[ unit ].header.unused4 = 0xFFFFFFFF;
530 memset ( g_Vmc_Image[ unit ].header.unused5, g_Vmc_Image[ unit ].erase_byte, 12 );
531 g_Vmc_Image[ unit ].header.max_used = ( 97 * g_Vmc_Image[ unit ].header.clusters_per_card ) / 100;
532 memset ( g_Vmc_Image[ unit ].header.unused6, g_Vmc_Image[ unit ].erase_byte, 8 );
533 g_Vmc_Image[ unit ].header.unused7 = 0xFFFFFFFF;
534
535 DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: mc_type : 0x%02x\n", g_Vmc_Image[ unit ].header.mc_type );
536 DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: mc_flag : 0x%02x\n", g_Vmc_Image[ unit ].header.mc_flag );
537
538 g_Vmc_Image[ unit ].last_free_cluster = g_Vmc_Image[ unit ].header.first_allocatable;
539
540 return 1;
541
542}
543
544
545//----------------------------------------------------------------------------
546// Used for timing functions, use this to optimize stuff
547//----------------------------------------------------------------------------
548#ifdef PROFILING
549
550 iop_sys_clock_t iop_clock_finished; // Global clock finished data
551
552 void profilerStart ( iop_sys_clock_t* iopclock )
553 {
554
555 GetSystemTime ( iopclock );
556
557 }
558
559 void profilerEnd ( const char* function, const char* name, iop_sys_clock_t* iopclock1 )
560 {
561
562 // Make this the first item, so we don't add time that need not be added
563 GetSystemTime ( &iop_clock_finished );
564
565 unsigned int sec1, usec1;
566 unsigned int sec2, usec2;
567
568 SysClock2USec ( &iop_clock_finished, &sec2, &usec2 );
569 SysClock2USec ( iopclock1, &sec1, &usec1 );
570
571 printf ( "vmcfs: Profiler[ %s ]: %s %ld. %ld seconds\n", function, name, sec2 - sec1, ( usec2 - usec1 ) / 1000 );
572
573 }
574
575#endif
576
577
578//----------------------------------------------------------------------------
579// Get date and time from cdvd fonction and put them into a "vmc_datetime" struct pointer.
580//----------------------------------------------------------------------------
581int getPs2Time ( vmc_datetime* tm )
582{
583
584 cd_clock_t cdtime;
585 s32 tmp;
586
587 static vmc_datetime timeBuf = {
588 0, 0x00, 0x00, 0x0A, 0x01, 0x01, 2008 // used if can not get time...
589 };
590
591 if ( CdReadClock ( &cdtime ) != 0 && cdtime.stat == 0 )
592 {
593
594 tmp = cdtime.second >> 4;
595 timeBuf.sec = ( unsigned int ) ( ( ( tmp << 2 ) + tmp ) << 1 ) + ( cdtime.second & 0x0F );
596 tmp = cdtime.minute >> 4;
597 timeBuf.min = ( ( ( tmp << 2 ) + tmp ) << 1 ) + ( cdtime.minute & 0x0F );
598 tmp = cdtime.hour >> 4;
599 timeBuf.hour = ( ( ( tmp << 2 ) + tmp ) << 1 ) + ( cdtime.hour & 0x0F );
600// timeBuf.hour = ( timeBuf.hour + 4 ) %24;// TEMP FIX ( need to deal with timezones? ) ... aparently not!
601 tmp = cdtime.day >> 4;
602 timeBuf.day = ( ( ( tmp << 2 ) + tmp ) << 1 ) + ( cdtime.day & 0x0F );
603 tmp = cdtime.month >> 4;
604 timeBuf.month = ( ( ( tmp << 2 ) + tmp ) << 1 ) + ( cdtime.month & 0x0F );
605 tmp = cdtime.year >> 4;
606 timeBuf.year = ( ( ( tmp << 2 ) + tmp ) << 1 ) + ( cdtime.year & 0xF ) + 2000;
607
608 }
609
610 memcpy ( tm, &timeBuf, sizeof ( vmc_datetime ) );
611
612 return 0;
613
614}
615
616
617//----------------------------------------------------------------------------
618// XOR table use for Error Correcting Code ( ECC ) calculation.
619//----------------------------------------------------------------------------
620const unsigned char ECC_XOR_Table[ 256 ]= {
6210x00, 0x87, 0x96, 0x11, 0xA5, 0x22, 0x33, 0xB4,
6220xB4, 0x33, 0x22, 0xA5, 0x11, 0x96, 0x87, 0x00,
6230xC3, 0x44, 0x55, 0xD2, 0x66, 0xE1, 0xF0, 0x77,
6240x77, 0xF0, 0xE1, 0x66, 0xD2, 0x55, 0x44, 0xC3,
6250xD2, 0x55, 0x44, 0xC3, 0x77, 0xF0, 0xE1, 0x66,
6260x66, 0xE1, 0xF0, 0x77, 0xC3, 0x44, 0x55, 0xD2,
6270x11, 0x96, 0x87, 0x00, 0xB4, 0x33, 0x22, 0xA5,
6280xA5, 0x22, 0x33, 0xB4, 0x00, 0x87, 0x96, 0x11,
6290xE1, 0x66, 0x77, 0xF0, 0x44, 0xC3, 0xD2, 0x55,
6300x55, 0xD2, 0xC3, 0x44, 0xF0, 0x77, 0x66, 0xE1,
6310x22, 0xA5, 0xB4, 0x33, 0x87, 0x00, 0x11, 0x96,
6320x96, 0x11, 0x00, 0x87, 0x33, 0xB4, 0xA5, 0x22,
6330x33, 0xB4, 0xA5, 0x22, 0x96, 0x11, 0x00, 0x87,
6340x87, 0x00, 0x11, 0x96, 0x22, 0xA5, 0xB4, 0x33,
6350xF0, 0x77, 0x66, 0xE1, 0x55, 0xD2, 0xC3, 0x44,
6360x44, 0xC3, 0xD2, 0x55, 0xE1, 0x66, 0x77, 0xF0,
6370xF0, 0x77, 0x66, 0xE1, 0x55, 0xD2, 0xC3, 0x44,
6380x44, 0xC3, 0xD2, 0x55, 0xE1, 0x66, 0x77, 0xF0,
6390x33, 0xB4, 0xA5, 0x22, 0x96, 0x11, 0x00, 0x87,
6400x87, 0x00, 0x11, 0x96, 0x22, 0xA5, 0xB4, 0x33,
6410x22, 0xA5, 0xB4, 0x33, 0x87, 0x00, 0x11, 0x96,
6420x96, 0x11, 0x00, 0x87, 0x33, 0xB4, 0xA5, 0x22,
6430xE1, 0x66, 0x77, 0xF0, 0x44, 0xC3, 0xD2, 0x55,
6440x55, 0xD2, 0xC3, 0x44, 0xF0, 0x77, 0x66, 0xE1,
6450x11, 0x96, 0x87, 0x00, 0xB4, 0x33, 0x22, 0xA5,
6460xA5, 0x22, 0x33, 0xB4, 0x00, 0x87, 0x96, 0x11,
6470xD2, 0x55, 0x44, 0xC3, 0x77, 0xF0, 0xE1, 0x66,
6480x66, 0xE1, 0xF0, 0x77, 0xC3, 0x44, 0x55, 0xD2,
6490xC3, 0x44, 0x55, 0xD2, 0x66, 0xE1, 0xF0, 0x77,
6500x77, 0xF0, 0xE1, 0x66, 0xD2, 0x55, 0x44, 0xC3,
6510x00, 0x87, 0x96, 0x11, 0xA5, 0x22, 0x33, 0xB4,
6520xB4, 0x33, 0x22, 0xA5, 0x11, 0x96, 0x87, 0x00,
653};
654
655
656//----------------------------------------------------------------------------
657// Calculate ECC for a 128 bytes chunk of data
658//----------------------------------------------------------------------------
659int calculateECC ( char* ECC_Chunk, const unsigned char* Data_Chunk )
660{
661 int i, c;
662
663 ECC_Chunk[ 0 ]= ECC_Chunk[ 1 ]= ECC_Chunk[ 2 ]= 0;
664
665 for ( i = 0; i < 0x80; i++ )
666 {
667
668 c = ECC_XOR_Table[ Data_Chunk[ i ] ];
669
670 ECC_Chunk[ 0 ] ^= c;
671
672 if ( c & 0x80 )
673 {
674
675 ECC_Chunk[ 1 ] ^= ~i;
676 ECC_Chunk[ 2 ] ^= i;
677
678 }
679
680 }
681
682 ECC_Chunk[ 0 ] = ~ECC_Chunk[ 0 ];
683 ECC_Chunk[ 0 ] &= 0x77;
684 ECC_Chunk[ 1 ] = ~ECC_Chunk[ 1 ];
685 ECC_Chunk[ 1 ] &= 0x7f;
686 ECC_Chunk[ 2 ] = ~ECC_Chunk[ 2 ];
687 ECC_Chunk[ 2 ] &= 0x7f;
688
689 return 1;
690
691}
692
693
694//----------------------------------------------------------------------------
695// Build ECC from a complet page of data
696//----------------------------------------------------------------------------
697int buildECC ( int unit, char* Page_Data, char* ECC_Data )
698{
699
700 char Data_Chunk[ 4 ][ 128 ];
701 char ECC_Chunk[ 4 ][ 3 ];
702 char ECC_Pad[ 4 ];
703
704 // This is to divide the page in 128 bytes chunks
705 memcpy ( Data_Chunk[ 0 ], Page_Data + 0, 128 );
706 memcpy ( Data_Chunk[ 1 ], Page_Data + 128, 128 );
707 memcpy ( Data_Chunk[ 2 ], Page_Data + 256, 128 );
708 memcpy ( Data_Chunk[ 3 ], Page_Data + 384, 128 );
709
710 // Ask for 128 bytes chunk ECC calculation, it returns 3 bytes per chunk
711 calculateECC ( ECC_Chunk[ 0 ], Data_Chunk[ 0 ]);
712 calculateECC ( ECC_Chunk[ 1 ], Data_Chunk[ 1 ]);
713 calculateECC ( ECC_Chunk[ 2 ], Data_Chunk[ 2 ]);
714 calculateECC ( ECC_Chunk[ 3 ], Data_Chunk[ 3 ]);
715
716 // Prepare Padding as ECC took only 12 bytes and stand on 16 bytes
717 memset ( ECC_Pad, g_Vmc_Image[ unit ].erase_byte, sizeof ( ECC_Pad ) );
718
719 // "MemCopy" our four 3 bytes ECC chunks into our 16 bytes ECC data buffer
720 // Finaly "MemCopy" our 4 bytes PAD chunks into last 4 bytes of our ECC data buffer
721 memcpy ( ECC_Data + 0, ECC_Chunk[ 0 ], 3 );
722 memcpy ( ECC_Data + 3, ECC_Chunk[ 1 ], 3 );
723 memcpy ( ECC_Data + 6, ECC_Chunk[ 2 ], 3 );
724 memcpy ( ECC_Data + 9, ECC_Chunk[ 3 ], 3 );
725 memcpy ( ECC_Data + 12, ECC_Pad , 4 );
726
727 return 1;
728
729}
Note: See TracBrowser for help on using the repository browser.