[1101] | 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 | }
|
---|