1 | #include "vmc.h"
|
---|
2 |
|
---|
3 |
|
---|
4 | // Misc fonctions
|
---|
5 |
|
---|
6 | //----------------------------------------------------------------------------
|
---|
7 | // Search a direntry corresponding to a path
|
---|
8 | //----------------------------------------------------------------------------
|
---|
9 | unsigned 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 | //----------------------------------------------------------------------------
|
---|
150 | unsigned 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 | //----------------------------------------------------------------------------
|
---|
205 | unsigned 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 | //----------------------------------------------------------------------------
|
---|
322 | void 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 | //----------------------------------------------------------------------------
|
---|
380 | unsigned 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 | //----------------------------------------------------------------------------
|
---|
438 | int 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 | //----------------------------------------------------------------------------
|
---|
581 | int 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 | //----------------------------------------------------------------------------
|
---|
620 | const unsigned char ECC_XOR_Table[ 256 ]= {
|
---|
621 | 0x00, 0x87, 0x96, 0x11, 0xA5, 0x22, 0x33, 0xB4,
|
---|
622 | 0xB4, 0x33, 0x22, 0xA5, 0x11, 0x96, 0x87, 0x00,
|
---|
623 | 0xC3, 0x44, 0x55, 0xD2, 0x66, 0xE1, 0xF0, 0x77,
|
---|
624 | 0x77, 0xF0, 0xE1, 0x66, 0xD2, 0x55, 0x44, 0xC3,
|
---|
625 | 0xD2, 0x55, 0x44, 0xC3, 0x77, 0xF0, 0xE1, 0x66,
|
---|
626 | 0x66, 0xE1, 0xF0, 0x77, 0xC3, 0x44, 0x55, 0xD2,
|
---|
627 | 0x11, 0x96, 0x87, 0x00, 0xB4, 0x33, 0x22, 0xA5,
|
---|
628 | 0xA5, 0x22, 0x33, 0xB4, 0x00, 0x87, 0x96, 0x11,
|
---|
629 | 0xE1, 0x66, 0x77, 0xF0, 0x44, 0xC3, 0xD2, 0x55,
|
---|
630 | 0x55, 0xD2, 0xC3, 0x44, 0xF0, 0x77, 0x66, 0xE1,
|
---|
631 | 0x22, 0xA5, 0xB4, 0x33, 0x87, 0x00, 0x11, 0x96,
|
---|
632 | 0x96, 0x11, 0x00, 0x87, 0x33, 0xB4, 0xA5, 0x22,
|
---|
633 | 0x33, 0xB4, 0xA5, 0x22, 0x96, 0x11, 0x00, 0x87,
|
---|
634 | 0x87, 0x00, 0x11, 0x96, 0x22, 0xA5, 0xB4, 0x33,
|
---|
635 | 0xF0, 0x77, 0x66, 0xE1, 0x55, 0xD2, 0xC3, 0x44,
|
---|
636 | 0x44, 0xC3, 0xD2, 0x55, 0xE1, 0x66, 0x77, 0xF0,
|
---|
637 | 0xF0, 0x77, 0x66, 0xE1, 0x55, 0xD2, 0xC3, 0x44,
|
---|
638 | 0x44, 0xC3, 0xD2, 0x55, 0xE1, 0x66, 0x77, 0xF0,
|
---|
639 | 0x33, 0xB4, 0xA5, 0x22, 0x96, 0x11, 0x00, 0x87,
|
---|
640 | 0x87, 0x00, 0x11, 0x96, 0x22, 0xA5, 0xB4, 0x33,
|
---|
641 | 0x22, 0xA5, 0xB4, 0x33, 0x87, 0x00, 0x11, 0x96,
|
---|
642 | 0x96, 0x11, 0x00, 0x87, 0x33, 0xB4, 0xA5, 0x22,
|
---|
643 | 0xE1, 0x66, 0x77, 0xF0, 0x44, 0xC3, 0xD2, 0x55,
|
---|
644 | 0x55, 0xD2, 0xC3, 0x44, 0xF0, 0x77, 0x66, 0xE1,
|
---|
645 | 0x11, 0x96, 0x87, 0x00, 0xB4, 0x33, 0x22, 0xA5,
|
---|
646 | 0xA5, 0x22, 0x33, 0xB4, 0x00, 0x87, 0x96, 0x11,
|
---|
647 | 0xD2, 0x55, 0x44, 0xC3, 0x77, 0xF0, 0xE1, 0x66,
|
---|
648 | 0x66, 0xE1, 0xF0, 0x77, 0xC3, 0x44, 0x55, 0xD2,
|
---|
649 | 0xC3, 0x44, 0x55, 0xD2, 0x66, 0xE1, 0xF0, 0x77,
|
---|
650 | 0x77, 0xF0, 0xE1, 0x66, 0xD2, 0x55, 0x44, 0xC3,
|
---|
651 | 0x00, 0x87, 0x96, 0x11, 0xA5, 0x22, 0x33, 0xB4,
|
---|
652 | 0xB4, 0x33, 0x22, 0xA5, 0x11, 0x96, 0x87, 0x00,
|
---|
653 | };
|
---|
654 |
|
---|
655 |
|
---|
656 | //----------------------------------------------------------------------------
|
---|
657 | // Calculate ECC for a 128 bytes chunk of data
|
---|
658 | //----------------------------------------------------------------------------
|
---|
659 | int 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 | //----------------------------------------------------------------------------
|
---|
697 | int 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 | }
|
---|