source: ps2launchargs/source/uLaunchELF/vmcfs/src/vmc_io.c@ 1120

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

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

  • Property svn:executable set to *
File size: 74.0 KB
Line 
1#include "vmc.h"
2
3
4// IO fonctions
5
6
7//----------------------------------------------------------------------------
8// Format a vmc file previously mounted with fileXioMount(.
9// mode can be FORMAT_FULL which mean erase all pages before formatting.
10// or FORMAT_FAST which skip erasing all pages before formatting.
11//----------------------------------------------------------------------------
12int Vmc_Format ( iop_file_t *f, const char *dev, const char *blockdev, void *arg, size_t arglen )
13{
14
15 if ( !g_Vmc_Initialized )
16 return VMCFS_ERR_INITIALIZED;
17
18 DEBUGPRINT ( 1, "vmcfs: format %d\n", f->unit );
19
20 int mode = FORMAT_FULL;
21
22 struct direntry dirent;
23 int all_sector;
24 char *mcbuffer, *mcbuffer2;
25 unsigned int i, j, k, x, y, last_blk_sector, Page_Num, Page_Num2;
26
27 Page_Num = 0;
28 Page_Num2 = 0;
29
30 if ( g_Vmc_Image[ f->unit ].fd < 0 )
31 return VMCFS_ERR_NOT_MOUNT;
32
33 PROF_START ( vmc_formatProf )
34
35 if ( mode == FORMAT_FULL )
36 {
37
38 for ( i = 0; i < g_Vmc_Image[ f->unit ].total_pages / g_Vmc_Image[ f->unit ].header.pages_per_block; i++ )
39 {
40
41 DEBUGPRINT ( 7, "vmcfs: format erasing block %d / %d\r", i, g_Vmc_Image[ f->unit ].total_pages / g_Vmc_Image[ f->unit ].header.pages_per_block );
42 eraseBlock ( g_Vmc_Image[ f->unit ].fd, i );
43
44 }
45
46 }
47
48 mcbuffer = ( char* )malloc ( ( g_Vmc_Image[ f->unit ].header.page_size + 0xFF ) & ~( unsigned int )0xFF );
49 mcbuffer2 = ( char* )malloc ( ( g_Vmc_Image[ f->unit ].header.page_size + 0xFF ) & ~( unsigned int )0xFF );
50
51 DEBUGPRINT ( 3, "vmcfs: format start\n" );
52
53 memset ( mcbuffer, g_Vmc_Image[ f->unit ].erase_byte, g_Vmc_Image[ f->unit ].header.page_size );
54 memcpy ( mcbuffer, &g_Vmc_Image[ f->unit ].header, sizeof ( struct superblock ) );
55
56 // Write header page
57 writePage ( g_Vmc_Image[ f->unit ].fd, mcbuffer, Page_Num );
58
59 Page_Num++;
60
61 DEBUGPRINT ( 3, "vmcfs: format indirect fat cluster\n" );
62
63 // goto fat table
64 for ( i = 1; i < ( g_Vmc_Image[ f->unit ].header.indir_fat_clusters[ 0 ]* g_Vmc_Image[ f->unit ].header.pages_per_cluster ); i++, Page_Num++ ) { }
65
66 all_sector = 0;
67 last_blk_sector = g_Vmc_Image[ f->unit ].header.indir_fat_clusters[ 0 ];
68
69 DEBUGPRINT ( 3, "vmcfs: format fat table\n" );
70
71 // Write fat table pages
72 for ( x = 0; g_Vmc_Image[ f->unit ].header.indir_fat_clusters[ x ]!= 0; x++ )
73 {
74
75 last_blk_sector = g_Vmc_Image[ f->unit ].header.indir_fat_clusters[ 0 ]+ x;
76 Page_Num = last_blk_sector * g_Vmc_Image[ f->unit ].header.pages_per_cluster;
77
78 for ( i = x * g_Vmc_Image[ f->unit ].header.pages_per_cluster; ( i < ( ( x + 1 ) * g_Vmc_Image[ f->unit ].header.pages_per_cluster ) ) && ( i <= ( ( g_Vmc_Image[ f->unit ].total_pages - 1 ) / 65536 ) ); i++, Page_Num++ )
79 {
80
81 memset ( mcbuffer, g_Vmc_Image[ f->unit ].erase_byte, g_Vmc_Image[ f->unit ].header.page_size );
82
83 for ( j = i * ( ( g_Vmc_Image[ f->unit ].header.page_size / 2 ) / g_Vmc_Image[ f->unit ].header.pages_per_cluster ), k = 0; ( j < i * ( ( g_Vmc_Image[ f->unit ].header.page_size / 2 ) / g_Vmc_Image[ f->unit ].header.pages_per_cluster ) + ( ( g_Vmc_Image[ f->unit ].header.page_size / 2 ) / g_Vmc_Image[ f->unit ].header.pages_per_cluster ) ) && ( j < ( ( g_Vmc_Image[ f->unit ].header.last_allocatable / ( g_Vmc_Image[ f->unit ].header.page_size / 2 ) ) + 1 ) ); j++, k++ )
84 {
85
86 ( ( unsigned int* ) mcbuffer )[ k ]= ( ( g_Vmc_Image[ f->unit ].total_pages - 1 ) / 65536 ) + last_blk_sector + 1 + j;
87
88 memset ( mcbuffer2, g_Vmc_Image[ f->unit ].erase_byte, g_Vmc_Image[ f->unit ].header.page_size );
89 Page_Num2 = ( ( unsigned int* ) mcbuffer )[ k ]* g_Vmc_Image[ f->unit ].header.pages_per_cluster;
90
91 for ( y = 0; ( y < ( ( g_Vmc_Image[ f->unit ].header.page_size / 2 ) / g_Vmc_Image[ f->unit ].header.pages_per_cluster ) ) && ( all_sector < g_Vmc_Image[ f->unit ].header.last_allocatable ); y++, all_sector++ )
92 {
93
94 if ( y == 0 && j == 0 && i == 0 )
95 {
96
97 ( ( unsigned int* ) mcbuffer2 )[ y ]= EOF_CLUSTER;
98
99 }
100 else
101 {
102
103 ( ( unsigned int* ) mcbuffer2 )[ y ]= FREE_CLUSTER;
104
105 }
106
107 }
108
109 writePage ( g_Vmc_Image[ f->unit ].fd, mcbuffer2, Page_Num2 );
110
111 Page_Num2++;
112 memset ( mcbuffer2, g_Vmc_Image[ f->unit ].erase_byte, g_Vmc_Image[ f->unit ].header.page_size );
113
114 for ( y = 0; ( y < ( ( g_Vmc_Image[ f->unit ].header.page_size / 2 ) / g_Vmc_Image[ f->unit ].header.pages_per_cluster ) ) && ( all_sector < g_Vmc_Image[ f->unit ].header.last_allocatable ); y++, all_sector++ )
115 {
116
117 ( ( unsigned int* ) mcbuffer2 )[ y ]= FREE_CLUSTER;
118
119 }
120
121 writePage ( g_Vmc_Image[ f->unit ].fd, mcbuffer2, Page_Num2 );
122
123 }
124
125 writePage ( g_Vmc_Image[ f->unit ].fd, mcbuffer, Page_Num );
126
127 }
128
129 }
130
131 DEBUGPRINT ( 3, "vmcfs: format root directory\n" );
132
133 Page_Num = g_Vmc_Image[ f->unit ].header.first_allocatable * g_Vmc_Image[ f->unit ].header.pages_per_cluster;
134
135 memset ( &dirent, 0, sizeof ( dirent ) );
136
137 dirent.mode = DF_EXISTS | DF_0400 | DF_DIRECTORY | DF_READ | DF_WRITE | DF_EXECUTE; // 0x8427
138 dirent.length = 2;
139 dirent.name[ 0 ] = '.';
140 getPs2Time ( &dirent.created );
141 getPs2Time ( &dirent.modified );
142
143 writePage ( g_Vmc_Image[ f->unit ].fd, ( unsigned char* ) &dirent, Page_Num );
144 Page_Num++;
145
146 memset ( &dirent, 0, sizeof ( dirent ) );
147
148 dirent.mode = DF_EXISTS | DF_HIDDEN | DF_0400 | DF_DIRECTORY | DF_WRITE | DF_EXECUTE; // 0xa426;
149 dirent.length = 0;
150 dirent.name[ 0 ] = '.';
151 dirent.name[ 1 ] = '.';
152 getPs2Time ( &dirent.created );
153 getPs2Time ( &dirent.modified );
154
155 writePage ( g_Vmc_Image[ f->unit ].fd, ( unsigned char* ) &dirent, Page_Num );
156
157 free ( mcbuffer );
158 free ( mcbuffer2 );
159
160 DEBUGPRINT ( 3, "vmcfs: format finished\n" );
161
162 PROF_END ( vmc_formatProf )
163
164 return VMCFS_ERR_NO;
165
166}
167
168
169//----------------------------------------------------------------------------
170// Open a file from vmc image. fileXioOpen("vmc...
171//----------------------------------------------------------------------------
172int Vmc_Open ( iop_file_t *f, const char *path1, int flags, int mode )
173{
174
175 if ( !g_Vmc_Initialized )
176 return VMCFS_ERR_INITIALIZED;
177
178 DEBUGPRINT ( 1, "vmcfs: Open %i %s\n", f->unit, path1 );
179
180 if ( g_Vmc_Image[ f->unit ].fd < 0 )
181 return VMCFS_ERR_NOT_MOUNT;
182
183 if ( g_Vmc_Image[ f->unit ].formated == FALSE )
184 return VMCFS_ERR_NOT_FORMATED;
185
186 PROF_START ( vmc_openProf )
187
188 struct direntry dirent;
189 struct file_privdata* fprivdata = malloc ( sizeof ( struct file_privdata ) );
190
191 if ( fprivdata == NULL )
192 return -1;
193
194 f->privdata = fprivdata;
195
196 fprivdata->gendata.fd = g_Vmc_Image[ f->unit ].fd;
197 fprivdata->gendata.first_allocatable = g_Vmc_Image[ f->unit ].header.first_allocatable;
198 fprivdata->gendata.last_allocatable = g_Vmc_Image[ f->unit ].header.last_allocatable;
199
200 memcpy ( fprivdata->gendata.indir_fat_clusters, g_Vmc_Image[ f->unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
201
202 unsigned int dirent_cluster = getDirentryFromPath ( &dirent, path1, &( fprivdata->gendata ), f->unit );
203
204 if ( dirent_cluster == ROOT_CLUSTER )
205 {
206
207 free ( fprivdata ); // Release the allocated memory
208
209 PROF_END ( vmc_openProf )
210
211 return -1; // File not found, could not be opened.
212
213 }
214 else if ( dirent_cluster == NOFOUND_CLUSTER )
215 {
216
217 if ( flags & O_CREAT )
218 {
219
220 DEBUGPRINT ( 2, "vmcfs: Open with O_CREAT.\n");
221
222 struct direntry parent;
223 unsigned int parent_cluster = 0;
224
225 char* path = malloc ( strlen ( path1 ) + 1 ); // + 1 for null terminator
226 memcpy ( path, path1, strlen ( path1 ) + 1 ); // create a local copy to work with
227
228 char* filename = strrchr ( path, '/' ); // last occurance of / , which should split the file name from the folders
229
230 // essentially splits path into 2 strings
231 filename[ 0 ]= '\0';
232 filename++;
233
234 DEBUGPRINT ( 2, "vmcfs: Creating file %s in parent folder %s\n", filename, path );
235
236 memset ( &dirent, 0, sizeof ( dirent ) );
237
238 // fill direntry file information
239 strcpy ( dirent.name, filename );
240 dirent.length = 0;
241 dirent.cluster = EOF_CLUSTER;
242 dirent.mode = DF_EXISTS | DF_0400 | DF_FILE | DF_READ | DF_WRITE | DF_EXECUTE; // 0x8417
243 getPs2Time ( &dirent.created );
244 getPs2Time ( &dirent.modified );
245
246 // we need to know this directories entry in its parent...
247 if ( path[ 0 ] == '\0' )
248 {
249
250 // get the root directories entry
251 parent_cluster = getDirentryFromPath ( &parent, ".", &( fprivdata->gendata ), f->unit );
252
253 }
254 else
255 {
256
257 // get the folder entry for the parent
258 parent_cluster = getDirentryFromPath ( &parent, path, &( fprivdata->gendata ), f->unit );
259
260 }
261
262 if ( parent_cluster == NOFOUND_CLUSTER )
263 {
264
265 DEBUGPRINT ( 3, "vmcfs: Unable to find parent directory.\n" );
266
267 free ( path );
268 free ( fprivdata ); // Release the allocated memory
269
270 PROF_END ( vmc_openProf )
271
272 return -1;
273
274 }
275
276 dirent_cluster = addObject ( &( fprivdata->gendata ), parent_cluster, &parent, &dirent, f->unit );
277
278 if ( dirent_cluster == ERROR_CLUSTER )
279 {
280
281 DEBUGPRINT ( 2, "vmcfs: open failed on %s\n", path1 );
282
283 free ( path );
284 free ( fprivdata ); // Release the allocated memory
285
286 PROF_END ( vmc_openProf )
287
288 return -1; // File not found, could not be opened.
289
290 }
291
292 free ( path );
293
294 }
295 else
296 {
297
298 free ( fprivdata ); // Release the allocated memory
299
300 PROF_END ( vmc_openProf )
301
302 return -1; // File not found, could not be opened.
303
304 }
305
306 }
307
308 if ( ( ! ( dirent.mode & DF_EXISTS ) ) || ( flags & O_TRUNC ) ) // File found but is hidden, or trunc the file
309 {
310
311 if ( flags & O_TRUNC )
312 DEBUGPRINT ( 3, "vmcfs: Open with O_TRUNC.\n");
313
314 int first_cluster = 1;
315 unsigned int current_cluster = 0;
316 unsigned int last_cluster = dirent.cluster;
317
318 DEBUGPRINT ( 4, "vmcfs: Searching last cluster of file ...\n" );
319
320 while ( 1 )
321 {
322
323 current_cluster = getFatEntry ( fprivdata->gendata.fd, last_cluster, fprivdata->gendata.indir_fat_clusters, FAT_VALUE );
324
325 if ( current_cluster == FREE_CLUSTER )
326 {
327
328 // FREE_CLUSTER mean last cluster of the hidden file is found
329 DEBUGPRINT ( 8, "vmcfs: Last cluster of file at %u\n", last_cluster );
330
331 break;
332
333 }
334 else if ( current_cluster == EOF_CLUSTER )
335 {
336
337 // EOF_CLUSTER mean last cluster of the file is found
338 DEBUGPRINT ( 8, "vmcfs: EOF_CLUSTER found.\n" );
339
340 setFatEntry ( fprivdata->gendata.fd, last_cluster, FREE_CLUSTER, fprivdata->gendata.indir_fat_clusters, FAT_SET );
341
342 break;
343
344 }
345 else
346 {
347
348 DEBUGPRINT ( 8, "vmcfs: Testing cluster %u ... value is %u\n", last_cluster, current_cluster );
349
350 // Otherwise set first cluster as eof and remaining clusters as free
351 if ( first_cluster == 1 )
352 {
353
354 setFatEntry ( fprivdata->gendata.fd, last_cluster, EOF_CLUSTER, fprivdata->gendata.indir_fat_clusters, FAT_SET );
355
356 dirent.length = 0;
357 dirent.cluster = EOF_CLUSTER;
358 dirent.mode = DF_EXISTS | DF_0400 | DF_FILE | DF_READ | DF_WRITE | DF_EXECUTE; // 0x8417
359 getPs2Time ( &dirent.created );
360 getPs2Time ( &dirent.modified );
361 writePage ( fprivdata->gendata.fd, ( unsigned char* ) &dirent, ( dirent_cluster + fprivdata->gendata.first_allocatable ) * g_Vmc_Image[ f->unit ].header.pages_per_cluster + fprivdata->gendata.dirent_page );
362
363 first_cluster = 0;
364
365 }
366 else
367 {
368
369 setFatEntry ( fprivdata->gendata.fd, last_cluster, FREE_CLUSTER, fprivdata->gendata.indir_fat_clusters, FAT_SET );
370
371 }
372
373 }
374
375 last_cluster = current_cluster;
376
377 }
378
379 }
380
381 // fill opened file informations
382 fprivdata->file_position = 0;
383 fprivdata->file_dirpage = ( dirent_cluster + fprivdata->gendata.first_allocatable ) * g_Vmc_Image[ f->unit ].header.pages_per_cluster + fprivdata->gendata.dirent_page;
384 fprivdata->file_cluster = dirent.cluster;
385 fprivdata->cluster_offset = 0;
386 fprivdata->file_startcluster = dirent.cluster;
387 fprivdata->file_length = dirent.length; // set the length to what it should be, and go from there
388
389 DEBUGPRINT ( 2, "vmcfs: File %s opened with length %u\n", path1, fprivdata->file_length );
390
391 PROF_END ( vmc_openProf )
392
393 return 1;
394
395}
396
397
398//----------------------------------------------------------------------------
399// Close a file previously open with fileXioOpen("vmc...
400//----------------------------------------------------------------------------
401int Vmc_Close ( iop_file_t* f )
402{
403
404 if ( !g_Vmc_Initialized )
405 return VMCFS_ERR_INITIALIZED;
406
407 DEBUGPRINT ( 1, "vmcfs: Close %i\n", f->unit );
408
409 if ( g_Vmc_Image[ f->unit ].fd < 0 )
410 return VMCFS_ERR_NOT_MOUNT;
411
412 if ( g_Vmc_Image[ f->unit ].formated == FALSE )
413 return VMCFS_ERR_NOT_FORMATED;
414
415 PROF_START ( vmc_closeProf )
416
417 struct file_privdata* fprivdata = f->privdata;
418
419 free ( fprivdata );
420
421 PROF_END ( vmc_closeProf )
422
423 return 0;
424
425}
426
427
428//----------------------------------------------------------------------------
429// Read a file previously open with fileXioOpen("vmc...
430//----------------------------------------------------------------------------
431int Vmc_Read ( iop_file_t* f, void* buffer, int size )
432{
433
434 if ( !g_Vmc_Initialized )
435 return VMCFS_ERR_INITIALIZED;
436
437 DEBUGPRINT ( 1, "vmcfs: Read %d bytes\n", size );
438
439 if ( g_Vmc_Image[ f->unit ].fd < 0 )
440 return VMCFS_ERR_NOT_MOUNT;
441
442 if ( g_Vmc_Image[ f->unit ].formated == FALSE )
443 return VMCFS_ERR_NOT_FORMATED;
444
445 PROF_START ( vmc_readProf )
446
447 if ( ! ( f->mode & O_RDONLY ) )
448 {
449
450 PROF_END ( vmc_readProf )
451
452 return -1; // if the file isn't opened for reading, return -1. No return eroor code from errno
453
454 }
455
456 struct file_privdata* fprivdata = f->privdata;
457
458 fprivdata->gendata.first_allocatable = g_Vmc_Image[ f->unit ].header.first_allocatable;
459 fprivdata->gendata.last_allocatable = g_Vmc_Image[ f->unit ].header.last_allocatable;
460
461 memcpy ( fprivdata->gendata.indir_fat_clusters, g_Vmc_Image[ f->unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
462
463 // we are at eof
464 if ( ( fprivdata->file_length - fprivdata->file_position ) == 0 )
465 {
466
467 PROF_END ( vmc_readProf )
468
469 return 0;
470
471 }
472
473 DEBUGPRINT ( 3, "vmcfs: Reading in %i bytes\n", size );
474
475 // we need to read in size, unless size is larger then length
476 if ( size > fprivdata->file_length - fprivdata->file_position )
477 {
478
479 DEBUGPRINT ( 3, "vmcfs: Adjusting size to read in to be %u\n", fprivdata->file_length - fprivdata->file_position );
480
481 size = fprivdata->file_length - fprivdata->file_position;
482
483 }
484
485 // Ok so we have been requested to read size bytes from the open file, which starts with fprivdata->file_cluster
486 // and our current position in the cluster is cluster_offset, while our overall position is file_position.
487 // We can determine what cluster in the link we should be in, by taking our overall position and dividing by 1024
488 // the size of a cluster.
489
490 int data_read = 0; // How much data we have read in so far
491 char* cluster_data; // Temporary storage for a cluster of data
492
493 cluster_data = ( char* )malloc ( ( g_Vmc_Image[ f->unit ].cluster_size + 0xFF ) & ~( unsigned int )0xFF );
494 memset ( cluster_data, 0, g_Vmc_Image[ f->unit ].cluster_size );
495
496 // While we still have data to read in
497 while ( data_read < size )
498 {
499
500 // Read in the file_cluster
501 readCluster ( fprivdata->gendata.fd, cluster_data, fprivdata->file_cluster + fprivdata->gendata.first_allocatable );
502
503 // We have 1024 bytes in cluster_data now, but we already read in cluster_offset bytes
504 // So we now need to copy whats left into the buffer that was passed to us
505
506 DEBUGPRINT ( 3, "vmcfs: There are %i bytes remaining\n", size - data_read );
507 DEBUGPRINT ( 3, "vmcfs: There are %i bytes left in cluster %u\n", ( fprivdata->cluster_offset == 0 ) ? 0 : g_Vmc_Image[ f->unit ].cluster_size - fprivdata->cluster_offset, fprivdata->file_cluster + fprivdata->gendata.first_allocatable );
508
509 // If the data remaining in a cluster is larger then the buffer passed to us, we can only read in size data
510 if ( size - data_read < g_Vmc_Image[ f->unit ].cluster_size - fprivdata->cluster_offset )
511 {
512
513 DEBUGPRINT ( 3, "vmcfs: Read in %i bytes\n", size );
514
515 memcpy ( buffer + data_read, cluster_data + fprivdata->cluster_offset, size - data_read );
516 fprivdata->cluster_offset += ( size - data_read );
517 data_read += ( size - data_read );
518
519 }
520 else // We can copy in the rest of the cluster, since there is space in the buffer passed to us
521 {
522
523 DEBUGPRINT ( 3, "vmcfs: Read in %i bytes\n", g_Vmc_Image[ f->unit ].cluster_size - fprivdata->cluster_offset );
524
525 memcpy ( buffer + data_read, cluster_data + fprivdata->cluster_offset, g_Vmc_Image[ f->unit ].cluster_size - fprivdata->cluster_offset );
526 data_read += ( g_Vmc_Image[ f->unit ].cluster_size - fprivdata->cluster_offset );
527 fprivdata->cluster_offset += ( g_Vmc_Image[ f->unit ].cluster_size - fprivdata->cluster_offset );
528
529 }
530
531 // If we have used up all of the data in a cluster, we need to tell it that the current cluster is the next one in the list
532 if ( fprivdata->cluster_offset == g_Vmc_Image[ f->unit ].cluster_size )
533 {
534
535 DEBUGPRINT ( 6, "vmcfs: Moving onto next cluster\n" );
536
537 fprivdata->file_cluster = getFatEntry ( fprivdata->gendata.fd, fprivdata->file_cluster, fprivdata->gendata.indir_fat_clusters, FAT_VALUE );
538 fprivdata->cluster_offset = 0;
539
540 }
541
542 }
543
544 free( cluster_data );
545
546 // Increase the file position by read
547 fprivdata->file_position += data_read;
548
549 PROF_END ( vmc_readProf )
550
551 // Return the amount read in.
552 return data_read;
553
554}
555
556
557//----------------------------------------------------------------------------
558// Write a file previously open with fileXioOpen("vmc...
559//----------------------------------------------------------------------------
560int Vmc_Write ( iop_file_t* f, void* buffer, int size )
561{
562
563 if ( !g_Vmc_Initialized )
564 return VMCFS_ERR_INITIALIZED;
565
566 DEBUGPRINT ( 1, "vmcfs: Write %i bytes\n", size );
567
568 if ( g_Vmc_Image[ f->unit ].fd < 0 )
569 return VMCFS_ERR_NOT_MOUNT;
570
571 if ( g_Vmc_Image[ f->unit ].formated == FALSE )
572 return VMCFS_ERR_NOT_FORMATED;
573
574 PROF_START ( vmc_writeProf )
575
576 if ( ! ( f->mode & O_WRONLY ) )
577 {
578
579 PROF_END ( vmc_writeProf )
580
581 return -1; // if the file isn't opened for writing, return -1
582
583 }
584
585 struct file_privdata* fprivdata = f->privdata;
586
587 fprivdata->gendata.first_allocatable = g_Vmc_Image[ f->unit ].header.first_allocatable;
588 fprivdata->gendata.last_allocatable = g_Vmc_Image[ f->unit ].header.last_allocatable;
589
590 memcpy ( fprivdata->gendata.indir_fat_clusters, g_Vmc_Image[ f->unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
591
592 if ( f->mode & O_APPEND ) {
593
594 DEBUGPRINT ( 8, "vmcfs: Write with O_APPEND.\n");
595
596 fprivdata->file_position = fprivdata->file_length;
597
598 }
599
600 unsigned int current_cluster;
601
602 // if we are going to go past the eof with this write
603 // we need to allocate some more free cluster space
604 int num_clusters = fprivdata->file_length / g_Vmc_Image[ f->unit ].cluster_size;
605
606 if ( ( fprivdata->file_length %g_Vmc_Image[ f->unit ].cluster_size ) > 0 )
607 num_clusters++;
608
609 DEBUGPRINT ( 5, "vmcfs: File lenght in cluster before this write: %u\n", num_clusters );
610
611 int num_clusters_required = ( fprivdata->file_position + size ) / g_Vmc_Image[ f->unit ].cluster_size;
612
613 if ( ( ( fprivdata->file_position + size ) %g_Vmc_Image[ f->unit ].cluster_size ) > 0 )
614 num_clusters_required++;
615
616 DEBUGPRINT ( 5, "vmcfs: File lenght in cluster after this write : %u\n", num_clusters_required );
617
618 if ( num_clusters_required > num_clusters )
619 {
620
621 fprivdata->file_length = fprivdata->file_position + size;
622
623 DEBUGPRINT ( 3, "vmcfs: File position: %u\n", fprivdata->file_position );
624 DEBUGPRINT ( 3, "vmcfs: Size to write: %u\n", size );
625 DEBUGPRINT ( 3, "vmcfs: File length : %u\n", fprivdata->file_length );
626
627 // now determine how many clusters we need forthis write
628 unsigned int clusters_needed = num_clusters_required - num_clusters;
629
630 DEBUGPRINT ( 3, "vmcfs: We need to allocate %u more clusters for storage\n", clusters_needed );
631
632 int i = 0;
633 unsigned int free_cluster = 0;
634 unsigned int last_cluster = 0;
635
636 if ( fprivdata->file_startcluster == EOF_CLUSTER )
637 {
638
639 free_cluster = getFreeCluster ( &( fprivdata->gendata ), f->unit );
640
641 if ( free_cluster == ERROR_CLUSTER )
642 {
643
644 DEBUGPRINT ( 2, "Not enough free space to add initial cluster. Aborting.\n" );
645
646 PROF_END ( vmc_writeProf )
647
648 return -1;
649
650 }
651
652 DEBUGPRINT ( 3, "vmcfs: Initial cluster at %u\n", free_cluster );
653
654 // mark the free cluster as eof
655 setFatEntry ( fprivdata->gendata.fd, free_cluster, EOF_CLUSTER, fprivdata->gendata.indir_fat_clusters, FAT_SET );
656
657 struct direntry dirent;
658
659 readPage ( fprivdata->gendata.fd, ( unsigned char* ) &dirent, fprivdata->file_dirpage );
660 dirent.cluster = free_cluster;
661 writePage ( fprivdata->gendata.fd, ( unsigned char* ) &dirent, fprivdata->file_dirpage );
662
663 fprivdata->file_startcluster = free_cluster;
664 fprivdata->file_cluster = free_cluster;
665
666 }
667 else
668 {
669
670 // loop to find the last cluster of the file.
671 last_cluster = fprivdata->file_startcluster;
672
673 DEBUGPRINT ( 3, "vmcfs: Searching last cluster of file\n" );
674
675 while ( 1 )
676 {
677
678 current_cluster = getFatEntry ( fprivdata->gendata.fd, last_cluster, fprivdata->gendata.indir_fat_clusters, FAT_VALUE );
679
680 if ( current_cluster == FREE_CLUSTER )
681 {
682
683 DEBUGPRINT ( 10, "vmcfs: Testing cluster %d ... value is FREE_CLUSTER\n", last_cluster );
684
685 }
686 else if ( current_cluster == EOF_CLUSTER )
687 {
688
689 DEBUGPRINT ( 10, "vmcfs: Testing cluster %d ... value is EOF_CLUSTER\n", i );
690 break;
691
692 }
693 else
694 {
695
696 DEBUGPRINT ( 10, "vmcfs: Testing cluster %d ... value is %d\n", last_cluster, current_cluster );
697
698 }
699
700 last_cluster = current_cluster;
701 i++;
702
703 }
704
705 DEBUGPRINT ( 3, "vmcfs: Last cluster of file at %u\n", last_cluster );
706
707 free_cluster = getFreeCluster ( &( fprivdata->gendata ), f->unit );
708
709 if ( free_cluster == ERROR_CLUSTER )
710 {
711
712 DEBUGPRINT ( 2, "Not enough free space to add restart cluster. Aborting.\n" );
713
714 PROF_END ( vmc_writeProf )
715
716 return -1;
717
718 }
719
720 DEBUGPRINT ( 3, "vmcfs: Restart cluster for the file at %u\n", free_cluster );
721
722 // mark the last cluster as restart of our file
723 setFatEntry ( fprivdata->gendata.fd, last_cluster, free_cluster, fprivdata->gendata.indir_fat_clusters, FAT_SET );
724
725 // mark the free cluster as eof
726 setFatEntry ( fprivdata->gendata.fd, free_cluster, EOF_CLUSTER, fprivdata->gendata.indir_fat_clusters, FAT_SET );
727
728 fprivdata->file_cluster = free_cluster;
729
730 }
731
732 clusters_needed--;
733 last_cluster = free_cluster;
734
735 // allocate free clusters for the space required.
736 for ( i = 0; i < clusters_needed; i++ )
737 {
738
739 free_cluster = getFreeCluster ( &( fprivdata->gendata ), f->unit );
740
741 if ( free_cluster == ERROR_CLUSTER )
742 {
743
744 DEBUGPRINT ( 2, "Not enough free space to add cluster to the chain. Aborting.\n" );
745
746 PROF_END ( vmc_writeProf )
747
748 return -1;
749
750 }
751
752 DEBUGPRINT ( 3, "vmcfs: Adding cluster %u to the chain for the file\n", free_cluster );
753
754 setFatEntry ( fprivdata->gendata.fd, last_cluster, free_cluster, fprivdata->gendata.indir_fat_clusters, FAT_SET );
755 last_cluster = free_cluster;
756
757 // mark the last cluster as eof
758 setFatEntry ( fprivdata->gendata.fd, last_cluster, EOF_CLUSTER, fprivdata->gendata.indir_fat_clusters, FAT_SET );
759
760 }
761
762 }
763
764 // ok space is definitly ready for us to write to...
765 current_cluster = fprivdata->file_cluster;
766
767 unsigned int data_written = 0;
768
769 while ( data_written < size )
770 {
771
772 // if we have more then a clusters worth of data to write...
773 int sizewritten = 0;
774
775 if ( ( size - data_written ) >= ( g_Vmc_Image[ f->unit ].cluster_size - fprivdata->cluster_offset ) )
776 {
777
778 if ( fprivdata->cluster_offset == 0 )
779 {
780
781 DEBUGPRINT ( 4, "vmcfs: Writing to cluster %u\n", current_cluster );
782
783 writeCluster ( fprivdata->gendata.fd, ( ( unsigned char* ) buffer ) + data_written, current_cluster + fprivdata->gendata.first_allocatable );
784 sizewritten = g_Vmc_Image[ f->unit ].cluster_size;
785
786 }
787 else
788 {
789
790 DEBUGPRINT ( 4, "vmcfs: Writing to cluster %u at offset %u for length %u\n", current_cluster, fprivdata->cluster_offset, g_Vmc_Image[ f->unit ].cluster_size - fprivdata->cluster_offset );
791
792 writeClusterPart ( fprivdata->gendata.fd, ( ( unsigned char* ) buffer ) + data_written, current_cluster + fprivdata->gendata.first_allocatable, fprivdata->cluster_offset, g_Vmc_Image[ f->unit ].cluster_size - fprivdata->cluster_offset );
793 sizewritten = g_Vmc_Image[ f->unit ].cluster_size - fprivdata->cluster_offset;
794
795 }
796
797 }
798 else
799 {
800
801 DEBUGPRINT ( 4, "vmcfs: Writing to cluster %u at offset %u for length %u\n", current_cluster, fprivdata->cluster_offset, size - data_written );
802
803 writeClusterPart ( fprivdata->gendata.fd, ( ( unsigned char* ) buffer ) + data_written, current_cluster + fprivdata->gendata.first_allocatable, fprivdata->cluster_offset, size - data_written );
804 sizewritten = size - data_written;
805
806 }
807
808 DEBUGPRINT ( 5, "vmcfs: Wrote %i bytes\n", sizewritten );
809
810 data_written += sizewritten;
811 fprivdata->file_position += sizewritten;
812 fprivdata->cluster_offset += sizewritten;
813
814 if ( fprivdata->cluster_offset == g_Vmc_Image[ f->unit ].cluster_size )
815 {
816
817 DEBUGPRINT ( 7, "vmcfs: Moving onto next cluster\n" );
818
819 current_cluster = getFatEntry ( fprivdata->gendata.fd, current_cluster, fprivdata->gendata.indir_fat_clusters, FAT_VALUE );
820 fprivdata->cluster_offset = 0;
821
822 }
823
824 }
825
826 struct direntry dirent;
827
828 if ( f->mode & O_TRUNC || f->mode & O_APPEND )
829 {
830
831 DEBUGPRINT ( 8, "vmcfs: Write with O_TRUNC.\n");
832
833 fprivdata->file_length = fprivdata->file_position;
834
835 }
836
837 readPage ( fprivdata->gendata.fd, ( unsigned char* ) &dirent, fprivdata->file_dirpage );
838
839 // Update file length
840 dirent.length = fprivdata->file_length;
841
842 // Update timestamp
843 getPs2Time ( &dirent.modified );
844
845 // Write this changes
846 writePage ( fprivdata->gendata.fd, ( unsigned char* ) &dirent, fprivdata->file_dirpage );
847
848 fprivdata->file_cluster = current_cluster;
849
850 PROF_END ( vmc_writeProf )
851
852 return data_written;
853
854}
855
856
857//----------------------------------------------------------------------------
858// Seek a file previously open with fileXioOpen("vmc...
859//----------------------------------------------------------------------------
860int Vmc_Lseek ( iop_file_t* f, unsigned long offset, int whence )
861{
862
863 if ( !g_Vmc_Initialized )
864 return VMCFS_ERR_INITIALIZED;
865
866 DEBUGPRINT ( 1, "vmcfs: Seek\n" );
867
868 if ( g_Vmc_Image[ f->unit ].fd < 0 )
869 return VMCFS_ERR_NOT_MOUNT;
870
871 if ( g_Vmc_Image[ f->unit ].formated == FALSE )
872 return VMCFS_ERR_NOT_FORMATED;
873
874 PROF_START ( vmc_lseekProf )
875
876 struct file_privdata* fprivdata = f->privdata;
877
878 switch ( whence ) {
879
880 case SEEK_SET:
881 fprivdata->file_position = offset;
882 break;
883
884 case SEEK_CUR:
885 fprivdata->file_position += offset;
886 break;
887
888 case SEEK_END:
889 fprivdata->file_position = fprivdata->file_length + offset;
890 break;
891
892 default:
893 return -1;
894
895 }
896
897 // Return an error if we are past the end of the file
898 if ( fprivdata->file_position > fprivdata->file_length )
899 return -1;
900
901 // Now we need to position cluster offsets to be correct
902 fprivdata->file_cluster = fprivdata->file_startcluster;
903
904 int i = 0;
905 int chainclusternum = fprivdata->file_position / g_Vmc_Image[ f->unit ].cluster_size;
906
907 for ( i = 0; i < chainclusternum; i++ )
908 fprivdata->file_cluster = getFatEntry ( fprivdata->gendata.fd, fprivdata->file_cluster, fprivdata->gendata.indir_fat_clusters, FAT_VALUE );
909
910 fprivdata->cluster_offset = fprivdata->file_position %g_Vmc_Image[ f->unit ].cluster_size;
911
912 PROF_END ( vmc_lseekProf )
913
914 return fprivdata->file_position;
915
916}
917
918
919//----------------------------------------------------------------------------
920// Control command.
921// IOCTL_VMCFS_RECOVER : Recover an object marked as none existing. ( data must be a valid path to an object in vmc file )
922//----------------------------------------------------------------------------
923int Vmc_Ioctl ( iop_file_t* f, unsigned long request, void* data )
924{
925
926 if ( !g_Vmc_Initialized )
927 return VMCFS_ERR_INITIALIZED;
928
929 switch ( request )
930 {
931
932 case IOCTL_VMCFS_RECOVER:
933 {
934
935 Vmc_Recover ( f->unit, ( char* ) data );
936
937 }
938 break;
939
940 default:
941
942 DEBUGPRINT ( 1, "vmcfs: Unrecognized ioctl command %ld\n", request );
943 break;
944
945 }
946
947 return VMCFS_ERR_NO;
948
949}
950
951
952//----------------------------------------------------------------------------
953// Remove an object from vmc image. Object can be a file or a folder.
954//----------------------------------------------------------------------------
955int Vmc_Remove ( iop_file_t* f, const char* path )
956{
957
958 if ( !g_Vmc_Initialized )
959 return VMCFS_ERR_INITIALIZED;
960
961 DEBUGPRINT ( 1, "vmcfs: remove %s\n", path );
962
963 if ( g_Vmc_Image[ f->unit ].fd < 0 )
964 return VMCFS_ERR_NOT_MOUNT;
965
966 if ( g_Vmc_Image[ f->unit ].formated == FALSE )
967 return VMCFS_ERR_NOT_FORMATED;
968
969 PROF_START ( vmc_removeProf )
970
971 struct direntry dirent;
972 struct gen_privdata gendata;
973
974 gendata.fd = g_Vmc_Image[ f->unit ].fd;
975 gendata.first_allocatable = g_Vmc_Image[ f->unit ].header.first_allocatable;
976 gendata.last_allocatable = g_Vmc_Image[ f->unit ].header.last_allocatable;
977
978 memcpy ( gendata.indir_fat_clusters, g_Vmc_Image[ f->unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
979
980 unsigned int dirent_cluster = getDirentryFromPath ( &dirent, path, &gendata, f->unit );
981
982 if ( dirent_cluster == ROOT_CLUSTER )
983 {
984
985 DEBUGPRINT ( 2, "vmcfs: remove failed. Root directory is protected.\n" );
986
987 PROF_END ( vmc_removeProf )
988
989 return -1;
990
991 }
992 else if ( dirent_cluster == NOFOUND_CLUSTER )
993 {
994
995 DEBUGPRINT ( 2, "vmcfs: remove failed. %s not found.\n", path );
996
997 PROF_END ( vmc_removeProf )
998
999 return -1;
1000
1001 }
1002
1003 if ( dirent.mode & DF_FILE )
1004 {
1005
1006 removeObject ( &gendata, dirent_cluster, &dirent, f->unit );
1007
1008 DEBUGPRINT ( 2, "vmcfs: file %s removed.\n", path );
1009
1010 }
1011 else
1012 {
1013
1014 DEBUGPRINT ( 2, "vmcfs: remove failed. %s is not a valid file.\n", path );
1015
1016 PROF_END ( vmc_removeProf )
1017
1018 return -1;
1019
1020 }
1021
1022 // ioman Bug Fix. mkdir is call after remove fonction
1023 g_Vmc_Remove_Flag = TRUE;
1024
1025 PROF_END ( vmc_removeProf )
1026
1027 return 0;
1028
1029}
1030
1031
1032//----------------------------------------------------------------------------
1033// Create a new folder into vmc image.
1034//----------------------------------------------------------------------------
1035int Vmc_Mkdir ( iop_file_t* f, const char* path1, int mode )
1036{
1037
1038 if ( !g_Vmc_Initialized )
1039 return VMCFS_ERR_INITIALIZED;
1040
1041 // ioman bug fix. mkdir is call after remove fonction
1042 if ( g_Vmc_Remove_Flag == TRUE )
1043 {
1044
1045 g_Vmc_Remove_Flag = FALSE;
1046 printf ( "vmcfs: mkdir stopped. Ioman bug fix.\n" );
1047 return 0;
1048
1049 }
1050
1051 DEBUGPRINT ( 1, "vmcfs: mkdir %s\n", path1 );
1052
1053 if ( g_Vmc_Image[ f->unit ].fd < 0 )
1054 return VMCFS_ERR_NOT_MOUNT;
1055
1056 if ( g_Vmc_Image[ f->unit ].formated == FALSE )
1057 return VMCFS_ERR_NOT_FORMATED;
1058
1059 PROF_START ( vmc_mkdirProf )
1060
1061 struct direntry dirent;
1062 struct gen_privdata gendata;
1063
1064 gendata.fd = g_Vmc_Image[ f->unit ].fd;
1065 gendata.first_allocatable = g_Vmc_Image[ f->unit ].header.first_allocatable;
1066 gendata.last_allocatable = g_Vmc_Image[ f->unit ].header.last_allocatable;
1067
1068 memcpy ( gendata.indir_fat_clusters, g_Vmc_Image[ f->unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
1069
1070 memset ( &dirent, 0, sizeof ( dirent ) );
1071
1072 // Make a local copy of path.
1073 char* path = malloc ( strlen ( path1 ) + 1 );
1074 memcpy ( path, path1, strlen ( path1 ) + 1 );
1075
1076 if ( path[ strlen ( path ) - 1 ] == '/' )
1077 path[ strlen ( path ) - 1 ]= '\0';
1078
1079 unsigned int dirent_cluster = getDirentryFromPath ( &dirent, path, &gendata, f->unit );
1080
1081 if ( dirent_cluster == ROOT_CLUSTER )
1082 {
1083
1084 DEBUGPRINT ( 2, "vmcfs: mkdir failed. Root directory is protected.\n" );
1085
1086 free( path );
1087
1088 PROF_END ( vmc_mkdirProf )
1089
1090 return -1; // File not found, could not be opened.
1091
1092 }
1093 else if ( dirent_cluster == NOFOUND_CLUSTER )
1094 {
1095
1096 struct direntry new_dirent;
1097 unsigned int new_dirent_cluster = 0;
1098 struct direntry parent_dirent;
1099 unsigned int parent_cluster = 0;
1100 struct gen_privdata parent_gendata;
1101
1102 parent_gendata.fd = g_Vmc_Image[ f->unit ].fd;
1103 parent_gendata.first_allocatable = g_Vmc_Image[ f->unit ].header.first_allocatable;
1104 parent_gendata.last_allocatable = g_Vmc_Image[ f->unit ].header.last_allocatable;
1105
1106 memcpy ( parent_gendata.indir_fat_clusters, g_Vmc_Image[ f->unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
1107
1108 // Find name of directory, and name of parent
1109 char* newdir = strrchr ( path, '/' );
1110
1111 newdir[ 0 ] = '\0';
1112 newdir++;
1113
1114 DEBUGPRINT ( 2, "vmcfs: Creating folder %s in parent folder %s\n", newdir, (path[0] == '\0') ? "Root" : path );
1115
1116 memset ( &new_dirent, 0, sizeof ( new_dirent ) );
1117
1118 // fill new direntry
1119 new_dirent.mode = DF_EXISTS | DF_0400 | DF_DIRECTORY | DF_READ | DF_WRITE | DF_EXECUTE; // 0x8427
1120 strcpy ( new_dirent.name, newdir );
1121 getPs2Time ( &new_dirent.created );
1122 getPs2Time ( &new_dirent.modified );
1123
1124 if ( path[ 0 ] == '\0' )
1125 {
1126
1127 // get the root directories entry
1128 parent_cluster = getDirentryFromPath ( &parent_dirent, ".", &parent_gendata, f->unit );
1129
1130 }
1131 else
1132 {
1133
1134 // get the folder entry for the parent
1135 parent_cluster = getDirentryFromPath ( &parent_dirent, path, &parent_gendata, f->unit );
1136
1137 }
1138
1139 if ( parent_cluster == NOFOUND_CLUSTER )
1140 {
1141
1142 DEBUGPRINT ( 3, "vmcfs: Unable to find parent directory\n" );
1143
1144 free ( path );
1145
1146 PROF_END ( vmc_mkdirProf )
1147
1148 return -1;
1149
1150 }
1151
1152 DEBUGPRINT ( 3, "vmcfs: Parent Information.\n" );
1153 DEBUGPRINT ( 3, "vmcfs: parent_cluster = %u\n", parent_cluster );
1154 DEBUGPRINT ( 3, "vmcfs: dir_cluster = %u\n", parent_dirent.cluster );
1155 DEBUGPRINT ( 3, "vmcfs: dirent.name = %s\n", parent_dirent.name );
1156 DEBUGPRINT ( 3, "vmcfs: dirent.length = %u\n", parent_dirent.length );
1157 DEBUGPRINT ( 3, "vmcfs: dirent.mode = %X\n", parent_dirent.mode );
1158 DEBUGPRINT ( 3, "vmcfs: dirent_page = %i\n", parent_gendata.dirent_page );
1159
1160 new_dirent_cluster = addObject ( &parent_gendata, parent_cluster, &parent_dirent, &new_dirent, f->unit );
1161
1162 if ( new_dirent_cluster == ERROR_CLUSTER )
1163 {
1164
1165 DEBUGPRINT ( 2, "vmcfs: mkdir failed on %s\n", path );
1166
1167 free ( path );
1168
1169 PROF_END ( vmc_mkdirProf )
1170
1171 return -1;
1172
1173 }
1174
1175 }
1176 else // directory allready exist, so test DF_EXISTS flag
1177 {
1178
1179 if ( dirent.mode & DF_EXISTS )
1180 {
1181
1182 DEBUGPRINT ( 2, "vmcfs: mkdir failed on %s. Directory allready exist.\n", path1 );
1183
1184 free( path );
1185
1186 PROF_END ( vmc_mkdirProf )
1187
1188 return -1;
1189
1190 }
1191 else
1192 {
1193
1194 DEBUGPRINT ( 8, "vmcfs: mkdir directory %s allready exist but is hidden. Changing attributs.\n", path1 );
1195
1196 DEBUGPRINT ( 8, "vmcfs: Following fat table cluster %u\n", dirent.cluster );
1197
1198 unsigned int pseudo_entry_cluster = getFatEntry ( gendata.fd, dirent.cluster, gendata.indir_fat_clusters, FAT_VALUE );
1199
1200 DEBUGPRINT ( 8, "vmcfs: Changing cluster mask of fat table cluster %u.\n", pseudo_entry_cluster );
1201
1202 // change cluster mask of the direntry
1203 setFatEntry ( gendata.fd, dirent.cluster, pseudo_entry_cluster, gendata.indir_fat_clusters, FAT_SET );
1204
1205 DEBUGPRINT ( 8, "vmcfs: Changing direntry %s attributs.\n", path1 );
1206
1207 // Update time stamp, and set dirent.mode to exist flag
1208 dirent.mode = dirent.mode | DF_EXISTS;
1209 getPs2Time ( &dirent.created );
1210 getPs2Time ( &dirent.modified );
1211 writePage ( gendata.fd, ( unsigned char* ) &dirent, ( dirent_cluster + gendata.first_allocatable ) * g_Vmc_Image[ f->unit ].header.pages_per_cluster + gendata.dirent_page );
1212
1213 DEBUGPRINT ( 8, "vmcfs: Restoring EOF cluster at %u.\n", pseudo_entry_cluster );
1214
1215 setFatEntry ( gendata.fd, pseudo_entry_cluster, EOF_CLUSTER, gendata.indir_fat_clusters, FAT_SET );
1216
1217 struct direntry pseudo_entries;
1218
1219 DEBUGPRINT ( 8, "vmcfs: Updating pseudo entries time stamps at cluster %u / page %u.\n", dirent.cluster + gendata.first_allocatable, ( dirent.cluster + gendata.first_allocatable ) * g_Vmc_Image[ f->unit ].header.pages_per_cluster );
1220
1221 // Update time stamp of '.' entry
1222 readPage ( gendata.fd, ( unsigned char* ) &pseudo_entries, ( dirent.cluster + gendata.first_allocatable ) * g_Vmc_Image[ f->unit ].header.pages_per_cluster );
1223 getPs2Time ( &pseudo_entries.created );
1224 getPs2Time ( &pseudo_entries.modified );
1225 writePage ( gendata.fd, ( unsigned char* ) &pseudo_entries, ( dirent.cluster + gendata.first_allocatable ) * g_Vmc_Image[ f->unit ].header.pages_per_cluster );
1226
1227 DEBUGPRINT ( 8, "vmcfs: Updating pseudo entries time stamps at cluster %u / page %u.\n", dirent.cluster + gendata.first_allocatable, ( dirent.cluster + gendata.first_allocatable ) * g_Vmc_Image[ f->unit ].header.pages_per_cluster + 1 );
1228
1229 // Update time stamp of '..' entry
1230 readPage ( gendata.fd, ( unsigned char* ) &pseudo_entries, ( dirent.cluster + gendata.first_allocatable ) * g_Vmc_Image[ f->unit ].header.pages_per_cluster + 1 );
1231 getPs2Time ( &pseudo_entries.created );
1232 getPs2Time ( &pseudo_entries.modified );
1233 writePage ( gendata.fd, ( unsigned char* ) &pseudo_entries, ( dirent.cluster + gendata.first_allocatable ) * g_Vmc_Image[ f->unit ].header.pages_per_cluster + 1 );
1234
1235 free( path );
1236
1237 }
1238
1239 }
1240
1241 DEBUGPRINT ( 3, "vmcfs: Directory %s created.\n", path1 );
1242
1243 PROF_END ( vmc_mkdirProf )
1244
1245 return 0;
1246
1247}
1248
1249
1250//----------------------------------------------------------------------------
1251// Remove a folder from vmc image.
1252//----------------------------------------------------------------------------
1253int Vmc_Rmdir ( iop_file_t* f, const char* path1 )
1254{
1255
1256 if ( !g_Vmc_Initialized )
1257 return VMCFS_ERR_INITIALIZED;
1258
1259 DEBUGPRINT ( 1, "vmcfs: rmdir %s\n", path1 );
1260
1261 if ( g_Vmc_Image[ f->unit ].fd < 0 )
1262 return VMCFS_ERR_NOT_MOUNT;
1263
1264 if ( g_Vmc_Image[ f->unit ].formated == FALSE )
1265 return VMCFS_ERR_NOT_FORMATED;
1266
1267 PROF_START ( vmc_rmdirProf )
1268
1269 struct direntry dirent;
1270 struct gen_privdata folder_gendata;
1271
1272 folder_gendata.fd = g_Vmc_Image[ f->unit ].fd;
1273 folder_gendata.first_allocatable = g_Vmc_Image[ f->unit ].header.first_allocatable;
1274 folder_gendata.last_allocatable = g_Vmc_Image[ f->unit ].header.last_allocatable;
1275
1276 memcpy ( folder_gendata.indir_fat_clusters, g_Vmc_Image[ f->unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
1277
1278 // Make a local copy of path
1279 char* path = malloc ( strlen ( path1 ) + 1 );
1280 memcpy ( path, path1, strlen ( path1 ) + 1 );
1281
1282 if ( path[ strlen ( path ) - 1 ] == '/' )
1283 path[ strlen ( path ) - 1 ]= '\0';
1284
1285 unsigned int dirent_cluster = getDirentryFromPath ( &dirent, path, &folder_gendata, f->unit );
1286
1287 if ( dirent_cluster == ROOT_CLUSTER )
1288 {
1289
1290 DEBUGPRINT ( 2, "vmcfs: rmdir failed. Root directory is protected.\n" );
1291
1292 free( path );
1293
1294 PROF_END ( vmc_rmdirProf )
1295
1296 return -1;
1297
1298 }
1299 else if ( dirent_cluster == NOFOUND_CLUSTER )
1300 {
1301
1302 DEBUGPRINT ( 2, "vmcfs: rmdir failed. %s not found.\n", path1 );
1303
1304 free( path );
1305
1306 PROF_END ( vmc_rmdirProf )
1307
1308 return -1;
1309
1310 }
1311
1312 if ( ! ( dirent.mode & DF_EXISTS ) )
1313 {
1314
1315 DEBUGPRINT ( 2, "vmcfs: rmdir failed. %s is allready removed.\n", path1 );
1316
1317 free( path );
1318
1319 PROF_END ( vmc_rmdirProf )
1320
1321 return -1;
1322
1323
1324 }
1325
1326 if ( dirent.mode & DF_DIRECTORY )
1327 {
1328
1329 // Find name of directory, and name of parent
1330 char* foldername = strrchr ( path, '/' );
1331
1332 foldername[ 0 ]= '\0';
1333 foldername++;
1334
1335 struct direntry child;
1336 unsigned int child_cluster;
1337 struct gen_privdata child_gendata;
1338 char* child_path;
1339
1340 child_path = ( char* )malloc ( MAX_PATH );
1341 memset ( child_path, 0, MAX_PATH );
1342
1343 int i = 0;
1344 int dir_number = 0;
1345 unsigned int search_cluster = dirent.cluster;
1346
1347 child_gendata.fd = g_Vmc_Image[ f->unit ].fd;
1348 child_gendata.first_allocatable = g_Vmc_Image[ f->unit ].header.first_allocatable;
1349 child_gendata.last_allocatable = g_Vmc_Image[ f->unit ].header.last_allocatable;
1350
1351 memcpy ( child_gendata.indir_fat_clusters, g_Vmc_Image[ f->unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
1352
1353 // remove file contained into the directory
1354 for ( i = 0; i < dirent.length; i++ )
1355 {
1356
1357 // read in the next directory entry
1358 readPage ( folder_gendata.fd, ( unsigned char* ) &child, ( search_cluster + folder_gendata.first_allocatable ) * g_Vmc_Image[ f->unit ].header.pages_per_cluster + dir_number );
1359
1360 // if child exist, remove it. But don't touch to pseudo entries.
1361 if ( child.mode & DF_EXISTS && i >= 2 )
1362 {
1363
1364 sprintf( child_path, "%s/%s/%s", path, dirent.name, child.name );
1365
1366 child_cluster = getDirentryFromPath ( &child, child_path, &child_gendata, f->unit );
1367
1368 if ( child_cluster != NOFOUND_CLUSTER )
1369 {
1370
1371 removeObject ( &child_gendata, child_cluster, &child, f->unit );
1372
1373 }
1374
1375 }
1376
1377 if ( dir_number == 1 )
1378 {
1379
1380 dir_number = 0;
1381 search_cluster = getFatEntry ( folder_gendata.fd, search_cluster, folder_gendata.indir_fat_clusters, FAT_VALUE );
1382
1383 }
1384 else
1385 {
1386
1387 dir_number = 1;
1388
1389 }
1390
1391 }
1392
1393 // finaly, remove directory
1394 removeObject ( &folder_gendata, dirent_cluster, &dirent, f->unit );
1395
1396 free( path );
1397 free( child_path );
1398
1399 }
1400 else
1401 {
1402
1403 DEBUGPRINT ( 2, "vmcfs: rmdir failed. %s is not a valid directory.\n", path1 );
1404
1405 free( path );
1406
1407 PROF_END ( vmc_rmdirProf )
1408
1409 return -1;
1410
1411 }
1412
1413 DEBUGPRINT ( 3, "vmcfs: Directory %s removed.\n", path1 );
1414
1415 // ioman Bug Fix. mkdir is call after remove fonction
1416 g_Vmc_Remove_Flag = TRUE;
1417
1418 PROF_END ( vmc_removeProf )
1419
1420 return 0;
1421
1422}
1423
1424
1425//----------------------------------------------------------------------------
1426// Open a folder in vmc image.
1427//----------------------------------------------------------------------------
1428int Vmc_Dopen ( iop_file_t* f, const char* path )
1429{
1430
1431 if ( !g_Vmc_Initialized )
1432 return VMCFS_ERR_INITIALIZED;
1433
1434 DEBUGPRINT ( 1, "vmcfs: dopen %i %s\n", f->unit, path );
1435
1436 if ( g_Vmc_Image[ f->unit ].fd < 0 )
1437 return VMCFS_ERR_NOT_MOUNT;
1438
1439 if ( g_Vmc_Image[ f->unit ].formated == FALSE )
1440 return VMCFS_ERR_NOT_FORMATED;
1441
1442 PROF_START ( vmc_dopenProf )
1443
1444 struct direntry dirent;
1445 struct dir_privdata* fprivdata = malloc ( sizeof ( struct dir_privdata ) );
1446
1447 if ( fprivdata == NULL )
1448 return -1;
1449
1450 f->privdata = fprivdata;
1451
1452 fprivdata->gendata.fd = g_Vmc_Image[ f->unit ].fd;
1453 fprivdata->gendata.first_allocatable = g_Vmc_Image[ f->unit ].header.first_allocatable;
1454
1455 memcpy ( fprivdata->gendata.indir_fat_clusters, g_Vmc_Image[ f->unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
1456
1457 unsigned int dirent_cluster = getDirentryFromPath ( &dirent, path, &( fprivdata->gendata ), f->unit );
1458
1459 if ( dirent_cluster == NOFOUND_CLUSTER )
1460 {
1461
1462 DEBUGPRINT ( 2, "vmcfs: dopen failed. %s not found.\n", path );
1463
1464 free ( fprivdata ); // Release the allocated memory
1465
1466 PROF_END ( vmc_dopenProf )
1467
1468 return -1; // Folder not found, could not be opened.
1469
1470 }
1471
1472 if ( ! ( dirent.mode & DF_EXISTS ) )
1473 {
1474
1475 DEBUGPRINT ( 2, "vmcfs: dopen failed. %s is hidden.\n", path );
1476
1477 free ( fprivdata ); // Release the allocated memory
1478
1479 PROF_END ( vmc_dopenProf )
1480
1481 return -1; // Folder not found, could not be opened.
1482
1483 }
1484
1485 fprivdata->dir_cluster = dirent.cluster;
1486 fprivdata->dir_length = dirent.length;
1487 fprivdata->dir_number = 0;
1488
1489 DEBUGPRINT ( 2, "vmcfs: Directory %s opened with length %u\n", path, fprivdata->dir_length );
1490
1491 PROF_END ( vmc_dopenProf )
1492
1493 return 1;
1494
1495}
1496
1497
1498//----------------------------------------------------------------------------
1499// Close a folder in vmc image.
1500//----------------------------------------------------------------------------
1501int Vmc_Dclose ( iop_file_t* f )
1502{
1503
1504 if ( !g_Vmc_Initialized )
1505 return VMCFS_ERR_INITIALIZED;
1506
1507 DEBUGPRINT ( 1, "vmcfs: dclose %i\n", f->unit );
1508
1509 if ( ( f->unit == 2 ) || ( f->unit == 3 ) )
1510 return 0; // Close our fake device used only for ioctl commands
1511
1512 PROF_START ( vmc_dcloseProf )
1513
1514 struct dir_privdata * fprivdata = f->privdata;
1515
1516 free ( fprivdata );
1517
1518 PROF_END ( vmc_dcloseProf )
1519
1520 return 0;
1521
1522}
1523
1524
1525//----------------------------------------------------------------------------
1526// Read the content of a folder in vmc image.
1527//----------------------------------------------------------------------------
1528int Vmc_Dread ( iop_file_t* f, iox_dirent_t *buffer )
1529{
1530
1531 if ( !g_Vmc_Initialized )
1532 return VMCFS_ERR_INITIALIZED;
1533
1534 DEBUGPRINT ( 1, "vmcfs: dread %i\n", f->unit );
1535
1536 if ( g_Vmc_Image[ f->unit ].fd < 0 )
1537 return VMCFS_ERR_NOT_MOUNT;
1538
1539 if ( g_Vmc_Image[ f->unit ].formated == FALSE )
1540 return VMCFS_ERR_NOT_FORMATED;
1541
1542 PROF_START ( vmc_dreadProf )
1543
1544 int next;
1545 vmc_datetime access_time;
1546 struct direntry dirent;
1547 struct dir_privdata * fprivdata = f->privdata;
1548 iox_dirent_t * buf = buffer;
1549
1550 memset ( buf, 0, sizeof ( iox_dirent_t ) );
1551
1552next_entry:
1553
1554 next = 0;
1555
1556 if ( fprivdata->dir_length == 0 )
1557 return -1;
1558
1559 // read in the next directory entry
1560 readPage ( fprivdata->gendata.fd, ( unsigned char* ) &dirent, ( fprivdata->dir_cluster + fprivdata->gendata.first_allocatable ) * g_Vmc_Image[ f->unit ].header.pages_per_cluster + fprivdata->dir_number );
1561
1562 DEBUGPRINT ( 4, "vmcfs: name: %s; cluster %u; length %u; mode 0x%02x\n", dirent.name, dirent.cluster, dirent.length, dirent.mode );
1563
1564 if ( dirent.mode & DF_EXISTS )
1565 {
1566
1567 buf->stat.mode = dirent.mode;
1568 buf->stat.attr = dirent.attr;
1569 buf->stat.size = dirent.length;
1570
1571 // File created Time / Date
1572 memcpy ( buf->stat.ctime, &dirent.created, sizeof ( vmc_datetime ) );
1573
1574 // File Modification Time / Date
1575 memcpy ( buf->stat.mtime, &dirent.modified, sizeof ( vmc_datetime ) );
1576
1577 // Last File Access Time : now
1578 getPs2Time ( &access_time );
1579 memcpy ( buf->stat.atime, &access_time, sizeof ( vmc_datetime ) );
1580
1581 buf->stat.hisize = 0; // No idea what hisize is?
1582
1583 strcpy ( buf->name, dirent.name );
1584
1585 }
1586 else
1587 {
1588
1589 next = 1;
1590
1591 }
1592
1593 fprivdata->dir_length--;
1594 // return 1 if there are more entries to read, otherwise return -1
1595
1596 if ( fprivdata->dir_number )
1597 {
1598
1599 fprivdata->dir_number = 0;
1600 fprivdata->dir_cluster = getFatEntry ( fprivdata->gendata.fd, fprivdata->dir_cluster, fprivdata->gendata.indir_fat_clusters, FAT_VALUE );
1601
1602 }
1603 else
1604 {
1605
1606 fprivdata->dir_number = 1;
1607
1608 }
1609
1610 if ( next == 1 )
1611 goto next_entry;
1612
1613 PROF_END ( vmc_dreadProf )
1614
1615 return 1;
1616
1617}
1618
1619
1620//----------------------------------------------------------------------------
1621// Get stats from an object in vmc image.
1622//----------------------------------------------------------------------------
1623int Vmc_Getstat ( iop_file_t* f, const char* path, iox_stat_t * stat )
1624{
1625
1626 if ( !g_Vmc_Initialized )
1627 return VMCFS_ERR_INITIALIZED;
1628
1629 DEBUGPRINT ( 1, "vmcfs: getstat %i %s\n", f->unit, path );
1630
1631 if ( g_Vmc_Image[ f->unit ].fd < 0 )
1632 return VMCFS_ERR_NOT_MOUNT;
1633
1634 if ( g_Vmc_Image[ f->unit ].formated == FALSE )
1635 return VMCFS_ERR_NOT_FORMATED;
1636
1637 PROF_START ( vmc_getstatProf )
1638
1639 struct direntry dirent;
1640 struct gen_privdata gendata;
1641 vmc_datetime access_time;
1642
1643 gendata.fd = g_Vmc_Image[ f->unit ].fd;
1644 gendata.first_allocatable = g_Vmc_Image[ f->unit ].header.first_allocatable;
1645 gendata.last_allocatable = g_Vmc_Image[ f->unit ].header.last_allocatable;
1646
1647 memcpy ( gendata.indir_fat_clusters, g_Vmc_Image[ f->unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
1648
1649 unsigned int dirent_cluster = getDirentryFromPath ( &dirent, path, &gendata, f->unit );
1650
1651 if ( dirent_cluster == NOFOUND_CLUSTER )
1652 {
1653
1654 DEBUGPRINT ( 2, "vmcfs: getstat failed. %s not found.\n", path );
1655
1656 PROF_END ( vmc_getstatProf )
1657
1658 return -1;
1659
1660 }
1661
1662 stat->mode = dirent.mode;
1663 stat->attr = dirent.attr;
1664 stat->size = dirent.length;
1665
1666 // File created Time / Date
1667 memcpy ( stat->ctime, &dirent.created, sizeof ( vmc_datetime ) );
1668
1669 // File Modification Time / Date
1670 memcpy ( stat->mtime, &dirent.modified, sizeof ( vmc_datetime ) );
1671
1672 // Last File Access Time : now
1673 getPs2Time ( &access_time );
1674 memcpy ( stat->atime, &access_time, sizeof ( vmc_datetime ) );
1675
1676 stat->hisize = 0; // No idea what hisize is?
1677
1678 PROF_END ( vmc_getstatProf )
1679
1680 return 0;
1681
1682}
1683
1684
1685//----------------------------------------------------------------------------
1686// Put stats to an object in vmc image.
1687//----------------------------------------------------------------------------
1688int Vmc_Chstat ( iop_file_t* f, const char* path, iox_stat_t * stat, unsigned int unknown )
1689{
1690
1691 if ( !g_Vmc_Initialized )
1692 return VMCFS_ERR_INITIALIZED;
1693
1694 DEBUGPRINT ( 1, "vmcfs: chstat %i %s\n", f->unit, path );
1695
1696 if ( g_Vmc_Image[ f->unit ].fd < 0 )
1697 return VMCFS_ERR_NOT_MOUNT;
1698
1699 if ( g_Vmc_Image[ f->unit ].formated == FALSE )
1700 return VMCFS_ERR_NOT_FORMATED;
1701
1702 PROF_START ( vmc_chstatProf )
1703
1704 struct direntry dirent;
1705 struct gen_privdata gendata;
1706
1707 gendata.fd = g_Vmc_Image[ f->unit ].fd;
1708 gendata.first_allocatable = g_Vmc_Image[ f->unit ].header.first_allocatable;
1709 gendata.last_allocatable = g_Vmc_Image[ f->unit ].header.last_allocatable;
1710
1711 memcpy ( gendata.indir_fat_clusters, g_Vmc_Image[ f->unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
1712
1713 unsigned int dirent_cluster = getDirentryFromPath ( &dirent, path, &gendata, f->unit );
1714
1715 if ( dirent_cluster == NOFOUND_CLUSTER )
1716 {
1717
1718 DEBUGPRINT ( 2, "vmcfs: chstat failed. %s not found.\n", path );
1719
1720 PROF_END ( vmc_chstatProf )
1721
1722 return -1;
1723
1724 }
1725
1726 dirent.mode = stat->mode;
1727 dirent.attr = stat->attr;
1728 dirent.length = stat->size;
1729
1730 // File created Time / Date
1731 memcpy ( &dirent.created, stat->ctime, sizeof ( vmc_datetime ) );
1732
1733 // File Modification Time / Date
1734 memcpy ( &dirent.created, stat->mtime, sizeof ( vmc_datetime ) );
1735
1736 // Write this change
1737 writePage ( gendata.fd, ( unsigned char* ) &dirent, ( dirent_cluster + gendata.first_allocatable ) * g_Vmc_Image[ f->unit ].header.pages_per_cluster + gendata.dirent_page );
1738
1739 PROF_END ( vmc_chstatProf )
1740
1741 return 0;
1742
1743}
1744
1745
1746// Start of extended io fonctions.
1747
1748
1749//----------------------------------------------------------------------------
1750// Rename an object into a vmc file.
1751//----------------------------------------------------------------------------
1752int Vmc_Rename ( iop_file_t* f, const char* path, const char* new_name )
1753{
1754
1755 if ( !g_Vmc_Initialized )
1756 return VMCFS_ERR_INITIALIZED;
1757
1758 DEBUGPRINT ( 1, "vmcfs: rename %s\n", path );
1759
1760 if ( g_Vmc_Image[ f->unit ].fd < 0 )
1761 return VMCFS_ERR_NOT_MOUNT;
1762
1763 if ( g_Vmc_Image[ f->unit ].formated == FALSE )
1764 return VMCFS_ERR_NOT_FORMATED;
1765
1766 PROF_START ( vmc_renameProf )
1767
1768 struct direntry dirent;
1769 struct gen_privdata gendata;
1770
1771 gendata.fd = g_Vmc_Image[ f->unit ].fd;
1772 gendata.first_allocatable = g_Vmc_Image[ f->unit ].header.first_allocatable;
1773 gendata.last_allocatable = g_Vmc_Image[ f->unit ].header.last_allocatable;
1774
1775 memcpy ( gendata.indir_fat_clusters, g_Vmc_Image[ f->unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
1776
1777 unsigned int dirent_cluster = getDirentryFromPath ( &dirent, path, &gendata, f->unit );
1778
1779 if ( dirent_cluster == ROOT_CLUSTER )
1780 {
1781
1782 DEBUGPRINT ( 2, "vmcfs: rename failed. Root directory is protected.\n" );
1783
1784 PROF_END ( vmc_renameProf )
1785
1786 return -1;
1787
1788 }
1789 else if ( dirent_cluster == NOFOUND_CLUSTER )
1790 {
1791
1792 DEBUGPRINT ( 2, "vmcfs: rename failed. %s not found.\n", path );
1793
1794 PROF_END ( vmc_renameProf )
1795
1796 return -1;
1797
1798 }
1799
1800 // Change the name of the object
1801 strcpy ( dirent.name, new_name );
1802
1803 // Update timestamp
1804 getPs2Time ( &dirent.modified );
1805
1806 // Write this change
1807 writePage ( gendata.fd, ( unsigned char* ) &dirent, ( dirent_cluster * g_Vmc_Image[ f->unit ].header.pages_per_cluster ) + gendata.dirent_page );
1808
1809 DEBUGPRINT ( 2, "vmcfs: Object %s renamed to %s\n", path, new_name );
1810
1811 PROF_END ( vmc_renameProf )
1812
1813 return 0;
1814
1815}
1816
1817
1818//----------------------------------------------------------------------------
1819// Not Implemented for the moment.
1820//----------------------------------------------------------------------------
1821int Vmc_Chdir ( iop_file_t* f, const char* path )
1822{
1823
1824 return VMCFS_ERR_IMPLEMENTED;
1825
1826}
1827
1828
1829//----------------------------------------------------------------------------
1830// Not Implemented for the moment.
1831//----------------------------------------------------------------------------
1832int Vmc_Sync ( iop_file_t* f, const char* device, int flag )
1833{
1834
1835 return VMCFS_ERR_IMPLEMENTED;
1836
1837}
1838
1839
1840//----------------------------------------------------------------------------
1841// Mount a vmc file with fileXioMount(... call.
1842//----------------------------------------------------------------------------
1843int Vmc_Mount ( iop_file_t* f, const char* fsname, const char* devname, int flag, void *arg, unsigned int arg_len )
1844{
1845 int errcode;
1846
1847 DEBUGPRINT ( 2, "vmcfs: Mount %s at mount point: %d\n", devname, f->unit );
1848
1849 if ( g_Vmc_Image[ f->unit ].fd >= 0 )
1850 return VMCFS_ERR_MOUNT_BUSY;
1851
1852 g_Vmc_Image[ f->unit ].fd = open ( devname, O_RDWR, 0x666 );
1853
1854 if ( g_Vmc_Image[ f->unit ].fd < 0 )
1855 {
1856 DEBUGPRINT ( 1, "vmcfs: Error opening vmc file %s\n", devname );
1857 DEBUGPRINT ( 1, "vmcfs: open error code: %d\n", g_Vmc_Image[ f->unit ].fd );
1858
1859 return VMCFS_ERR_VMC_OPEN;
1860 }
1861
1862 // read informations from the superblock
1863 int r = read ( g_Vmc_Image[ f->unit ].fd, &g_Vmc_Image[ f->unit ].header, sizeof ( struct superblock ) );
1864
1865 if ( r != sizeof ( struct superblock ) )
1866 {
1867 DEBUGPRINT ( 1, "vmcfs: Error reading vmc file %s\n", devname );
1868 DEBUGPRINT ( 1, "vmcfs: fd: %d, error code:%d\n", g_Vmc_Image[ f->unit ].fd, r );
1869
1870 errcode = VMCFS_ERR_VMC_READ;
1871
1872mountAbort:
1873 close ( g_Vmc_Image[ f->unit ].fd );
1874 g_Vmc_Image[ f->unit ].fd = VMCFS_ERR_NOT_MOUNT;
1875 return errcode;
1876 }
1877
1878 g_Vmc_Image[ f->unit ].card_size = lseek ( g_Vmc_Image[ f->unit ].fd, 0, SEEK_END );
1879 lseek ( g_Vmc_Image[ f->unit ].fd, 0, SEEK_SET );
1880
1881 if( g_Vmc_Image[ f->unit ].header.magic[ 0 ] != 'S'
1882 || g_Vmc_Image[ f->unit ].header.magic[ 1 ] != 'o'
1883 || g_Vmc_Image[ f->unit ].header.magic[ 2 ] != 'n'
1884 || g_Vmc_Image[ f->unit ].header.magic[ 3 ] != 'y'
1885 || g_Vmc_Image[ f->unit ].header.magic[ 4 ] != ' '
1886 || g_Vmc_Image[ f->unit ].header.magic[ 5 ] != 'P'
1887 || g_Vmc_Image[ f->unit ].header.magic[ 6 ] != 'S'
1888 || g_Vmc_Image[ f->unit ].header.magic[ 7 ] != '2'
1889 || g_Vmc_Image[ f->unit ].header.magic[ 8 ] != ' '
1890 || g_Vmc_Image[ f->unit ].header.magic[ 9 ] != 'M'
1891 || g_Vmc_Image[ f->unit ].header.magic[ 10 ] != 'e'
1892 || g_Vmc_Image[ f->unit ].header.magic[ 11 ] != 'm'
1893 || g_Vmc_Image[ f->unit ].header.magic[ 12 ] != 'o'
1894 || g_Vmc_Image[ f->unit ].header.magic[ 13 ] != 'r'
1895 || g_Vmc_Image[ f->unit ].header.magic[ 14 ] != 'y'
1896 || g_Vmc_Image[ f->unit ].header.magic[ 15 ] != ' '
1897 || g_Vmc_Image[ f->unit ].header.magic[ 16 ] != 'C'
1898 || g_Vmc_Image[ f->unit ].header.magic[ 17 ] != 'a'
1899 || g_Vmc_Image[ f->unit ].header.magic[ 18 ] != 'r'
1900 || g_Vmc_Image[ f->unit ].header.magic[ 19 ] != 'd'
1901 || g_Vmc_Image[ f->unit ].header.magic[ 20 ] != ' '
1902 || g_Vmc_Image[ f->unit ].header.magic[ 21 ] != 'F'
1903 || g_Vmc_Image[ f->unit ].header.magic[ 22 ] != 'o'
1904 || g_Vmc_Image[ f->unit ].header.magic[ 23 ] != 'r'
1905 || g_Vmc_Image[ f->unit ].header.magic[ 24 ] != 'm'
1906 || g_Vmc_Image[ f->unit ].header.magic[ 25 ] != 'a'
1907 || g_Vmc_Image[ f->unit ].header.magic[ 26 ] != 't'
1908 )
1909 {
1910 // Card is not formated
1911 DEBUGPRINT ( 1, "vmcfs: Warning vmc file %s is not formated\n", devname );
1912 if ( !setDefaultSpec ( f->unit ) )
1913 {
1914 // Card size error
1915 DEBUGPRINT ( 1, "vmcfs: Error size of vmc file %s is incompatible\n", devname );
1916
1917 errcode = VMCFS_ERR_VMC_SIZE;
1918 goto mountAbort;
1919 }
1920 g_Vmc_Image[ f->unit ].formated = FALSE;
1921 }else{
1922 g_Vmc_Image[ f->unit ].formated = TRUE;
1923
1924 DEBUGPRINT ( 4, "vmcfs: SuperBlock readed from vmc file %s.\n", devname );
1925
1926 DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: magic[40] : %s\n" , g_Vmc_Image[ f->unit ].header.magic );
1927 DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: page_size : 0x%02x\n", g_Vmc_Image[ f->unit ].header.page_size );
1928 DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: pages_per_cluster : 0x%02x\n", g_Vmc_Image[ f->unit ].header.pages_per_cluster );
1929 DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: pages_per_block : 0x%02x\n", g_Vmc_Image[ f->unit ].header.pages_per_block );
1930 DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: clusters_per_card : 0x%02x\n", g_Vmc_Image[ f->unit ].header.clusters_per_card );
1931 DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: first_allocatable : 0x%02x\n", g_Vmc_Image[ f->unit ].header.first_allocatable );
1932 DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: last_allocatable : 0x%02x\n", g_Vmc_Image[ f->unit ].header.last_allocatable );
1933 DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: root_cluster : 0x%02x\n", g_Vmc_Image[ f->unit ].header.root_cluster );
1934 DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: backup_block1 : 0x%02x\n", g_Vmc_Image[ f->unit ].header.backup_block1 );
1935 DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: backup_block2 : 0x%02x\n", g_Vmc_Image[ f->unit ].header.backup_block2 );
1936 for ( r = 0; g_Vmc_Image[ f->unit ].header.indir_fat_clusters[ r ]!= 0; r++ )
1937 DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: indir_fat_clusters[%d] : 0x%02x\n", r, g_Vmc_Image[ f->unit ].header.indir_fat_clusters[ r ]);
1938 DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: mc_type : 0x%02x\n", g_Vmc_Image[ f->unit ].header.mc_type );
1939 DEBUGPRINT ( 4, "vmcfs: SuperBlock Info: mc_flag : 0x%02x\n", g_Vmc_Image[ f->unit ].header.mc_flag );
1940
1941 if ( g_Vmc_Image[ f->unit ].header.mc_type != PS2_MEMORYCARD )
1942 {
1943 // Card is not a PS2 one
1944 DEBUGPRINT ( 1, "vmcfs: Error vmc file %s is not a valid PS2 image\n", devname );
1945
1946 errcode = VMCFS_ERR_CARD_TYPE;
1947 goto mountAbort;
1948 }
1949
1950 //Reaching this point means we have a valid PS2 image
1951 DEBUGPRINT ( 4, "vmcfs: Image file Info: Vmc card type : %s MemoryCard.\n", ( g_Vmc_Image[ f->unit ].header.mc_type == PSX_MEMORYCARD ? "PSX" : ( g_Vmc_Image[ f->unit ].header.mc_type == PS2_MEMORYCARD ? "PS2" : "PDA" ) ) );
1952
1953 g_Vmc_Image[ f->unit ].total_pages = g_Vmc_Image[ f->unit ].header.pages_per_cluster * g_Vmc_Image[ f->unit ].header.clusters_per_card;
1954 g_Vmc_Image[ f->unit ].cluster_size = g_Vmc_Image[ f->unit ].header.page_size * g_Vmc_Image[ f->unit ].header.pages_per_cluster;
1955 g_Vmc_Image[ f->unit ].erase_byte = ( g_Vmc_Image[ f->unit ].header.mc_flag & 0x10 ) ? 0x0 : 0xFF;
1956 g_Vmc_Image[ f->unit ].last_idc = EOF_CLUSTER;
1957 g_Vmc_Image[ f->unit ].last_cluster = EOF_CLUSTER;
1958 g_Vmc_Image[ f->unit ].last_free_cluster = g_Vmc_Image[ f->unit ].header.first_allocatable;
1959
1960 memset ( &g_Vmc_Image[ f->unit ].indirect_cluster, g_Vmc_Image[ f->unit ].erase_byte, MAX_CLUSTER_SIZE );
1961 memset ( &g_Vmc_Image[ f->unit ].fat_cluster, g_Vmc_Image[ f->unit ].erase_byte, MAX_CLUSTER_SIZE );
1962
1963 if ( g_Vmc_Image[ f->unit ].card_size == ( ( g_Vmc_Image[ f->unit ].header.page_size + 0x10 ) * g_Vmc_Image[ f->unit ].total_pages ) )
1964 {
1965 g_Vmc_Image[ f->unit ].ecc_flag = TRUE;
1966 }
1967 else if ( g_Vmc_Image[ f->unit ].card_size == ( g_Vmc_Image[ f->unit ].header.page_size * g_Vmc_Image[ f->unit ].total_pages ) )
1968 {
1969 g_Vmc_Image[ f->unit ].ecc_flag = FALSE;
1970 }
1971 else
1972 {
1973 // Card size error
1974 DEBUGPRINT ( 1, "vmcfs: Error size of vmc file %s is incompatible\n", devname );
1975 errcode = VMCFS_ERR_VMC_SIZE;
1976 goto mountAbort;
1977 }
1978
1979 DEBUGPRINT ( 4, "vmcfs: Image file Info: Number of pages : %d\n", g_Vmc_Image[ f->unit ].total_pages );
1980 DEBUGPRINT ( 4, "vmcfs: Image file Info: Size of a cluster : %d bytes\n", g_Vmc_Image[ f->unit ].cluster_size );
1981 DEBUGPRINT ( 4, "vmcfs: Image file Info: ECC shunk found : %s\n", g_Vmc_Image[ f->unit ].ecc_flag ? "YES" : "NO" );
1982 }
1983
1984 if ( g_Vmc_Image[ f->unit ].formated == FALSE ){
1985 errcode = VMCFS_ERR_NOT_FORMATED;
1986 goto mountAbort;
1987 }
1988
1989 return 0;
1990}
1991
1992//----------------------------------------------------------------------------
1993// Unmount a vmc file previously mounted with fileXioMount(
1994//----------------------------------------------------------------------------
1995int Vmc_Umount ( iop_file_t* f, const char* fsname )
1996{
1997
1998 DEBUGPRINT ( 2, "vmcfs: UnMount %s at mount point: %d\n", fsname, f->unit );
1999
2000 close ( g_Vmc_Image[ f->unit ].fd );
2001 g_Vmc_Image[ f->unit ].fd = VMCFS_ERR_NOT_MOUNT;
2002
2003 return 0;
2004
2005}
2006
2007//----------------------------------------------------------------------------
2008// Not Implemented for the moment.
2009//----------------------------------------------------------------------------
2010int Vmc_Lseek64 ( iop_file_t* f, long long offset, int whence )
2011{
2012
2013 return VMCFS_ERR_IMPLEMENTED;
2014
2015}
2016
2017
2018//----------------------------------------------------------------------------
2019// Control command.
2020// DEVCTL_VMCFS_CLEAN : Set as free all fat cluster corresponding to a none existing object. ( Object are just marked as none existing but not removed from fat table when rmdir or remove fonctions are call. This allow to recover a deleted file. )
2021// DEVCTL_VMCFS_CKFREE : Check free space available on vmc file.
2022//----------------------------------------------------------------------------
2023int Vmc_Devctl ( iop_file_t* f, const char* path, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen )
2024{
2025
2026 if ( !g_Vmc_Initialized )
2027 return VMCFS_ERR_INITIALIZED;
2028
2029 switch ( cmd )
2030 {
2031
2032 case DEVCTL_VMCFS_CLEAN:
2033 {
2034
2035 Vmc_Clean ( f->unit );
2036
2037 }
2038 break;
2039
2040 case DEVCTL_VMCFS_CKFREE:
2041 {
2042
2043 unsigned int free_space = Vmc_Checkfree ( f->unit );
2044
2045 return free_space;
2046
2047 }
2048 break;
2049
2050 default:
2051
2052 DEBUGPRINT ( 1, "vmcfs: Unrecognized devctl command %d\n", cmd );
2053 break;
2054
2055 }
2056
2057 return VMCFS_ERR_NO;
2058
2059}
2060
2061
2062//----------------------------------------------------------------------------
2063// Not Implemented for the moment.
2064//----------------------------------------------------------------------------
2065int Vmc_Symlink ( iop_file_t* f, const char* old, const char* new )
2066{
2067
2068 return VMCFS_ERR_IMPLEMENTED;
2069
2070}
2071
2072
2073//----------------------------------------------------------------------------
2074// Not Implemented for the moment.
2075//----------------------------------------------------------------------------
2076int Vmc_Readlink ( iop_file_t* f, const char* path, char* buf, unsigned int buf_len )
2077{
2078
2079 return VMCFS_ERR_IMPLEMENTED;
2080
2081}
2082
2083
2084//----------------------------------------------------------------------------
2085// Not Implemented for the moment.
2086//----------------------------------------------------------------------------
2087int Vmc_Ioctl2 ( iop_file_t* f, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen )
2088{
2089
2090 return VMCFS_ERR_IMPLEMENTED;
2091
2092}
2093
2094
2095// Extanded ioctl fonctions.
2096
2097
2098//----------------------------------------------------------------------------
2099// Recover an object in vmc image after removing it.
2100// Not working properly when object have been overwrited
2101//----------------------------------------------------------------------------
2102int Vmc_Recover ( int unit, const char* path1 )
2103{
2104
2105 if ( !g_Vmc_Initialized )
2106 return VMCFS_ERR_INITIALIZED;
2107
2108 DEBUGPRINT ( 1, "vmcfs: recover %s\n", path1 );
2109
2110 if ( g_Vmc_Image[ unit ].fd < 0 )
2111 return VMCFS_ERR_NOT_MOUNT;
2112
2113 if ( g_Vmc_Image[ unit ].formated == FALSE )
2114 return VMCFS_ERR_NOT_FORMATED;
2115
2116 PROF_START ( vmc_recoverProf )
2117
2118 struct direntry dirent;
2119 struct gen_privdata gendata;
2120
2121 gendata.fd = g_Vmc_Image[ unit ].fd;
2122 gendata.first_allocatable = g_Vmc_Image[ unit ].header.first_allocatable;
2123 gendata.last_allocatable = g_Vmc_Image[ unit ].header.last_allocatable;
2124
2125 memcpy ( gendata.indir_fat_clusters, g_Vmc_Image[ unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
2126
2127 // Make a local copy of path.
2128 char* path = malloc ( strlen ( path1 ) - strlen ( "vmc0:" ) + 1 );
2129 memcpy ( path, path1 + strlen ( "vmc0:" ), strlen ( path1 ) - strlen ( "vmc0:" ) + 1 );
2130
2131 if ( path[ strlen ( path ) - 1 ] == '/' )
2132 path[ strlen ( path ) - 1 ]= '\0';
2133
2134 unsigned int dirent_cluster = getDirentryFromPath ( &dirent, path, &gendata, unit );
2135
2136 if ( dirent_cluster == ROOT_CLUSTER )
2137 {
2138
2139 DEBUGPRINT ( 2, "vmcfs: recover failed. Root directory is protected.\n" );
2140
2141 free( path );
2142
2143 PROF_END ( vmc_recoverProf )
2144
2145 return -1;
2146
2147 }
2148 else if ( dirent_cluster == NOFOUND_CLUSTER )
2149 {
2150
2151 DEBUGPRINT ( 2, "vmcfs: recover failed. %s not found.\n", path1 );
2152
2153 free( path );
2154
2155 PROF_END ( vmc_recoverProf )
2156
2157 return -1;
2158
2159 }
2160
2161 struct direntry parent;
2162 struct gen_privdata parent_gendata;
2163 unsigned int parent_cluster = 0;
2164
2165 parent_gendata.fd = g_Vmc_Image[ unit ].fd;
2166 parent_gendata.first_allocatable = g_Vmc_Image[ unit ].header.first_allocatable;
2167 parent_gendata.last_allocatable = g_Vmc_Image[ unit ].header.last_allocatable;
2168
2169 memcpy ( parent_gendata.indir_fat_clusters, g_Vmc_Image[ unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
2170
2171 // Find name of file, and name of parent
2172 char* filename = strrchr ( path, '/' );
2173
2174 filename[ 0 ] = '\0';
2175 filename++;
2176
2177 DEBUGPRINT ( 4, "vmcfs: Checking attributs parent directory %s\n", path );
2178
2179 if ( path[ 0 ] == '\0' )
2180 {
2181
2182 // get the root directories entry
2183 parent_cluster = getDirentryFromPath ( &parent, ".", &parent_gendata, unit );
2184
2185 }
2186 else
2187 {
2188
2189 // get the folder entry for the parent
2190 parent_cluster = getDirentryFromPath ( &parent, path, &parent_gendata, unit );
2191
2192 }
2193
2194 if ( parent_cluster == NOFOUND_CLUSTER )
2195 {
2196
2197 DEBUGPRINT ( 3, "vmcfs: Unable to recover %s. Parent directory not found.\n", path1 );
2198
2199 free ( path );
2200
2201 PROF_END ( vmc_recoverProf )
2202
2203 return -1;
2204
2205 }
2206
2207 DEBUGPRINT ( 6, "vmcfs: Parent Information.\n" );
2208 DEBUGPRINT ( 6, "vmcfs: parent_cluster = %u\n", parent_cluster );
2209 DEBUGPRINT ( 6, "vmcfs: dir_cluster = %u\n", parent.cluster );
2210 DEBUGPRINT ( 6, "vmcfs: dirent.name = %s\n", parent.name );
2211 DEBUGPRINT ( 6, "vmcfs: dirent.length = %u\n", parent.length );
2212 DEBUGPRINT ( 6, "vmcfs: dirent.mode = %X\n", parent.mode );
2213 DEBUGPRINT ( 6, "vmcfs: dirent_page = %i\n", parent_gendata.dirent_page );
2214
2215 if ( ! ( parent.mode & DF_EXISTS ) )
2216 {
2217
2218 DEBUGPRINT ( 3, "vmcfs: Unable to restore %s. Parent directory %s is hidden.\n", path1, path );
2219
2220 free ( path );
2221
2222 PROF_END ( vmc_recoverProf )
2223
2224 return -1;
2225
2226 }
2227
2228 if ( dirent.mode & DF_DIRECTORY ) // directory case
2229 {
2230
2231 if ( dirent.mode & DF_EXISTS )
2232 {
2233
2234 DEBUGPRINT ( 2, "vmcfs: recover failed on %s. Directory allready exist.\n", path1 );
2235
2236 free( path );
2237
2238 PROF_END ( vmc_recoverProf )
2239
2240 return -1;
2241
2242 }
2243 else
2244 {
2245
2246 DEBUGPRINT ( 8, "vmcfs: recover directory %s allready exist but is hidden. Changing attributs.\n", path1 );
2247
2248 DEBUGPRINT ( 8, "vmcfs: Following fat table cluster %u\n", dirent.cluster );
2249
2250 unsigned int pseudo_entry_cluster = getFatEntry ( gendata.fd, dirent.cluster, gendata.indir_fat_clusters, FAT_VALUE );
2251
2252 DEBUGPRINT ( 8, "vmcfs: Changing cluster mask of fat table cluster %u.\n", pseudo_entry_cluster );
2253
2254 // change cluster mask of the direntry
2255 setFatEntry ( gendata.fd, dirent.cluster, pseudo_entry_cluster, gendata.indir_fat_clusters, FAT_SET );
2256
2257 DEBUGPRINT ( 8, "vmcfs: Changing direntry %s attributs.\n", path1 );
2258
2259 // Update time stamp, and set dirent.mode to exist flag
2260 dirent.mode = dirent.mode | DF_EXISTS;
2261 getPs2Time ( &dirent.created );
2262 getPs2Time ( &dirent.modified );
2263 writePage ( gendata.fd, ( unsigned char* ) &dirent, ( dirent_cluster + gendata.first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster + gendata.dirent_page );
2264
2265 DEBUGPRINT ( 8, "vmcfs: Restoring EOF cluster at %u.\n", pseudo_entry_cluster );
2266
2267 setFatEntry ( gendata.fd, pseudo_entry_cluster, EOF_CLUSTER, gendata.indir_fat_clusters, FAT_SET );
2268
2269 struct direntry pseudo_entries;
2270
2271 DEBUGPRINT ( 8, "vmcfs: Updating pseudo entries time stamps at cluster %u / page %u.\n", dirent.cluster + gendata.first_allocatable, ( dirent.cluster + gendata.first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster );
2272
2273 // Update time stamp of '.' entry
2274 readPage ( gendata.fd, ( unsigned char* ) &pseudo_entries, ( dirent.cluster + gendata.first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster );
2275 getPs2Time ( &pseudo_entries.created );
2276 getPs2Time ( &pseudo_entries.modified );
2277 writePage ( gendata.fd, ( unsigned char* ) &pseudo_entries, ( dirent.cluster + gendata.first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster );
2278
2279 DEBUGPRINT ( 8, "vmcfs: Updating pseudo entries time stamps at cluster %u / page %u.\n", dirent.cluster + gendata.first_allocatable, ( dirent.cluster + gendata.first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster + 1 );
2280
2281 // Update time stamp of '..' entry
2282 readPage ( gendata.fd, ( unsigned char* ) &pseudo_entries, ( dirent.cluster + gendata.first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster + 1 );
2283 getPs2Time ( &pseudo_entries.created );
2284 getPs2Time ( &pseudo_entries.modified );
2285 writePage ( gendata.fd, ( unsigned char* ) &pseudo_entries, ( dirent.cluster + gendata.first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster + 1 );
2286
2287 DEBUGPRINT ( 2, "vmcfs: Directory %s recovered.\n", path1 );
2288
2289 free( path );
2290
2291 goto end;
2292
2293 }
2294
2295 }
2296 else // file case
2297 {
2298
2299 if ( dirent.mode & DF_EXISTS )
2300 {
2301
2302 DEBUGPRINT ( 2, "vmcfs: recover failed on %s. File allready exist.\n", path );
2303
2304 free( path );
2305
2306 PROF_END ( vmc_recoverProf )
2307
2308 return -1;
2309
2310 }
2311 else
2312 {
2313
2314 unsigned int current_cluster = 0;
2315 unsigned int last_cluster = dirent.cluster;
2316
2317 DEBUGPRINT ( 8, "vmcfs: Restoring fat table clusters of file %s\n", filename );
2318
2319 while ( 1 )
2320 {
2321
2322 current_cluster = getFatEntry ( gendata.fd, last_cluster, gendata.indir_fat_clusters, FAT_VALUE );
2323
2324 if ( current_cluster == FREE_CLUSTER )
2325 {
2326
2327 // FREE_CLUSTER mean last cluster of the direntry is found
2328 DEBUGPRINT ( 8, "vmcfs: Last cluster of file at %u\n", last_cluster );
2329
2330 DEBUGPRINT ( 8, "vmcfs: Restoring End Of File at fat table cluster %u\n", last_cluster );
2331
2332 setFatEntry ( gendata.fd, last_cluster, EOF_CLUSTER, gendata.indir_fat_clusters, FAT_SET );
2333
2334 break;
2335
2336 }
2337 else if ( current_cluster == EOF_CLUSTER )
2338 {
2339
2340 // EOF_CLUSTER mean nothing to create or error, so goto end
2341 DEBUGPRINT ( 3, "vmcfs: Error. EOF_CLUSTER found !!!\n" );
2342
2343 free( path );
2344
2345 goto end;
2346
2347 }
2348 else
2349 {
2350
2351 // Otherwise set cluster as free
2352 DEBUGPRINT ( 10, "vmcfs: Testing cluster %u ... value is %u\n", last_cluster, current_cluster );
2353
2354 DEBUGPRINT ( 8, "vmcfs: Restoring cluster mask at fat table cluster %u\n", last_cluster );
2355
2356 setFatEntry ( gendata.fd, last_cluster, current_cluster, gendata.indir_fat_clusters, FAT_SET );
2357
2358 }
2359
2360 last_cluster = current_cluster;
2361
2362 }
2363
2364 DEBUGPRINT ( 8, "vmcfs: Restoring direntry at cluster %u / page %u\n", dirent_cluster + gendata.first_allocatable, ( dirent.cluster + gendata.first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster + gendata.dirent_page );
2365
2366 dirent.mode = dirent.mode | DF_EXISTS;
2367 getPs2Time ( &dirent.created );
2368 getPs2Time ( &dirent.modified );
2369 writePage ( gendata.fd, ( unsigned char* ) &dirent, ( dirent_cluster + gendata.first_allocatable ) * g_Vmc_Image[ unit ].header.pages_per_cluster + gendata.dirent_page );
2370
2371 free( path );
2372
2373 DEBUGPRINT ( 3, "vmcfs: File %s restored.\n", path1 );
2374
2375 }
2376
2377 }
2378
2379end:
2380
2381 PROF_END ( vmc_recoverProf )
2382
2383 return 0;
2384
2385}
2386
2387
2388//----------------------------------------------------------------------------
2389// Check actual free space of the vmc file.
2390//----------------------------------------------------------------------------
2391unsigned int Vmc_Checkfree ( int unit )
2392{
2393
2394 if ( !g_Vmc_Initialized )
2395 return VMCFS_ERR_INITIALIZED;
2396
2397 DEBUGPRINT ( 1, "vmcfs: check free %d\n", unit );
2398
2399 if ( g_Vmc_Image[ unit ].fd < 0 )
2400 return VMCFS_ERR_NOT_MOUNT;
2401
2402 if ( g_Vmc_Image[ unit ].formated == FALSE )
2403 return VMCFS_ERR_NOT_FORMATED;
2404
2405 PROF_START ( vmc_checkfreeProf )
2406
2407 int i = 0;
2408 unsigned int cluster_value = 0;
2409 unsigned int cluster_mask = 0;
2410 unsigned int free_space = 0;
2411 unsigned int free_cluster_num = 0;
2412 struct gen_privdata gendata;
2413
2414 gendata.fd = g_Vmc_Image[ unit ].fd;
2415 gendata.first_allocatable = g_Vmc_Image[ unit ].header.first_allocatable;
2416 gendata.last_allocatable = g_Vmc_Image[ unit ].header.last_allocatable;
2417
2418 memcpy ( gendata.indir_fat_clusters, g_Vmc_Image[ unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
2419
2420 for ( i = gendata.first_allocatable; i < gendata.last_allocatable; i++ )
2421 {
2422
2423 cluster_value = getFatEntry ( gendata.fd, i - gendata.first_allocatable, gendata.indir_fat_clusters, FAT_VALUE );
2424
2425 if ( cluster_value == FREE_CLUSTER )
2426 {
2427
2428 DEBUGPRINT ( 10, "vmcfs: Testing cluster %d ... value is FREE_CLUSTER\n", i );
2429
2430 DEBUGPRINT ( 6, "vmcfs: Free cluster found at %d\n", i );
2431
2432 free_cluster_num++;
2433
2434 }
2435 else if ( cluster_value == EOF_CLUSTER )
2436 {
2437
2438 DEBUGPRINT ( 10, "vmcfs: Testing cluster %d ... value is EOF_CLUSTER\n", i );
2439
2440 }
2441 else
2442 {
2443
2444 DEBUGPRINT ( 10, "vmcfs: Testing cluster %d ... value is %u\n", i, cluster_value );
2445
2446 cluster_mask = getFatEntry ( gendata.fd, i - gendata.first_allocatable, gendata.indir_fat_clusters, FAT_MASK );
2447
2448 if ( cluster_mask != MASK_CLUSTER )
2449 {
2450
2451 DEBUGPRINT ( 6, "vmcfs: Free cluster found at %d\n", i );
2452
2453 free_cluster_num++;
2454
2455 }
2456
2457 }
2458
2459 }
2460
2461 free_space = free_cluster_num * g_Vmc_Image[ unit ].cluster_size;
2462
2463 PROF_END ( vmc_checkfreeProf )
2464
2465 DEBUGPRINT ( 3, "vmcfs: Total free space: %u\n", free_space );
2466
2467 return free_space;
2468
2469}
2470
2471
2472//----------------------------------------------------------------------------
2473// Clean unused cluster of the vmc file.
2474//----------------------------------------------------------------------------
2475int Vmc_Clean ( int unit )
2476{
2477
2478 if ( !g_Vmc_Initialized )
2479 return VMCFS_ERR_INITIALIZED;
2480
2481 DEBUGPRINT ( 1, "vmcfs: clean %d\n", unit );
2482
2483 if ( g_Vmc_Image[ unit ].fd < 0 )
2484 return VMCFS_ERR_NOT_MOUNT;
2485
2486 if ( g_Vmc_Image[ unit ].formated == FALSE )
2487 return VMCFS_ERR_NOT_FORMATED;
2488
2489 PROF_START ( vmc_cleanProf )
2490
2491 int i = 0;
2492 unsigned int cluster_value = 0;
2493 unsigned int cluster_mask = 0;
2494 int object_remove = FALSE;
2495 struct gen_privdata gendata;
2496
2497 gendata.fd = g_Vmc_Image[ unit ].fd;
2498 gendata.first_allocatable = g_Vmc_Image[ unit ].header.first_allocatable;
2499 gendata.last_allocatable = g_Vmc_Image[ unit ].header.last_allocatable;
2500
2501 memcpy ( gendata.indir_fat_clusters, g_Vmc_Image[ unit ].header.indir_fat_clusters, sizeof ( unsigned int ) * 32 );
2502
2503 for ( i = gendata.first_allocatable; i < gendata.last_allocatable; i++ )
2504 {
2505
2506 cluster_value = getFatEntry ( gendata.fd, i - gendata.first_allocatable, gendata.indir_fat_clusters, FAT_VALUE );
2507
2508 if ( cluster_value == FREE_CLUSTER )
2509 {
2510
2511 DEBUGPRINT ( 10, "vmcfs: Testing cluster %d ... value is FREE_CLUSTER\n", i );
2512
2513 }
2514 else if ( cluster_value == EOF_CLUSTER )
2515 {
2516
2517 DEBUGPRINT ( 10, "vmcfs: Testing cluster %d ... value is EOF_CLUSTER\n", i );
2518
2519 }
2520 else
2521 {
2522
2523 DEBUGPRINT ( 10, "vmcfs: Testing cluster %d ... value is %u\n", i, cluster_value );
2524
2525 cluster_mask = getFatEntry ( gendata.fd, i - gendata.first_allocatable, gendata.indir_fat_clusters, FAT_MASK );
2526
2527 if ( cluster_mask != MASK_CLUSTER )
2528 {
2529
2530 DEBUGPRINT ( 6, "vmcfs: Setting cluster %d as free cluster.\n", i );
2531
2532 setFatEntry ( gendata.fd, i - gendata.first_allocatable, FREE_CLUSTER, gendata.indir_fat_clusters, FAT_SET );
2533
2534 object_remove = TRUE;
2535
2536 }
2537
2538 }
2539
2540 }
2541
2542 return 0;
2543
2544}
Note: See TracBrowser for help on using the repository browser.