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