| 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 | } |