Main Page | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

fs.c

00001 /*
00002  *      This program is free software; you can redistribute it and/or
00003  *      modify it under the terms of the GNU General Public License
00004  *      as published by the Free Software Foundation; either version
00005  *      2 of the License, or (at your option) any later version.
00006  *
00007  *  Copyright 1999-2004 Michael Klein <michael(dot)klein(at)puffin(dot)lb(dot)shuttle(dot)de>
00008 */
00009 
00010 #ifdef SAVE_RCSID
00011 static char *rcsid =
00012     "@(#) $Id: fs.c,v 1.18 2006/03/10 15:20:24 trikalio Exp $";
00013 #endif
00014 
00015 #include "d64copy_int.h"
00016 
00017 #include <stdio.h>
00018 #include <stdlib.h>
00019 #include <string.h>
00020 
00021 #include "arch.h"
00022 
00023 static d64copy_settings *fs_settings;
00024 
00025 static FILE *the_file;
00026 static char *error_map;
00027 static int block_count;
00028 
00029 static int block_offset(int tr, int se)
00030 {
00031     int sectors = 0, i;
00032     for(i = 1; i < tr; i++)
00033     {
00034         sectors += d64copy_sector_count(fs_settings->two_sided, i);
00035     }
00036     return (sectors + se) * BLOCKSIZE;
00037 }
00038 
00039 static int read_block(__u_char tr, __u_char se, __u_char *block)
00040 {
00041     if(fseek(the_file, block_offset(tr, se), SEEK_SET) == 0)
00042     {
00043         return fread(block, BLOCKSIZE, 1, the_file) != 1;
00044     }
00045     return 1;
00046 }
00047 
00048 /*
00049  * Variables to make sure writing the block is an atomary process
00050  */
00051 static int atom_execute = 0;
00052 static __u_char atom_tr;
00053 static __u_char atom_se;
00054 static const unsigned char *atom_blk;
00055 static int atom_size;
00056 static int atom_read_status;
00057 
00058 static int write_block(__u_char tr, __u_char se, const unsigned char *blk, int size, int read_status)
00059 {
00060     long ofs;
00061     int ret;
00062 
00063     atom_tr = tr;
00064     atom_se = se;
00065     atom_blk = blk;
00066     atom_size = size;
00067     atom_read_status = read_status;
00068 
00069     atom_execute = 1;
00070 
00071     ofs = block_offset(tr, se);
00072     if(fseek(the_file, ofs, SEEK_SET) == 0)
00073     {
00074         error_map[ofs / BLOCKSIZE] = (char) read_status;
00075         ret = fwrite(blk, size, 1, the_file) != 1;
00076     }
00077     else
00078     {
00079         ret = 1;
00080     }
00081 
00082     atom_execute = 0;
00083 
00084     return ret;
00085 }
00086 
00087 static int open_disk(CBM_FILE fd, d64copy_settings *settings,
00088                      const void *arg, int for_writing,
00089                      turbo_start start, d64copy_message_cb message_cb)
00090 {
00091     off_t filesize;
00092     int stat_ok, is_image, error_info;
00093     int tr = 0;
00094     char *name = (char*)arg;
00095 
00096     the_file = NULL;
00097     fs_settings = settings;
00098     block_count = 0;
00099 
00100     stat_ok = arch_filesize(name, &filesize) == 0;
00101     is_image = error_info = 0;
00102 
00103     if(stat_ok)
00104     {
00105         if(filesize == D71_BLOCKS * BLOCKSIZE)
00106         {
00107             is_image = 1;
00108             block_count = D71_BLOCKS;
00109             tr = D71_TRACKS;
00110         }
00111         else if(filesize == D71_BLOCKS * (BLOCKSIZE + 1))
00112         {
00113             is_image = 1;
00114             error_info = 1;
00115             block_count = D71_BLOCKS;
00116             tr = D71_TRACKS;
00117         }
00118         else
00119         {
00120             block_count = STD_BLOCKS;
00121             for( tr = STD_TRACKS; !is_image && tr <= TOT_TRACKS; )
00122             {
00123                 is_image = filesize == block_count * BLOCKSIZE;
00124                 if(!is_image)
00125                 {
00126                     error_info = is_image =
00127                         filesize == block_count * (BLOCKSIZE + 1);
00128                 }
00129                 if(!is_image)
00130                 {
00131                     block_count += d64copy_sector_count( 0, tr++ );
00132                 }
00133             }
00134             if( is_image && tr != STD_TRACKS )
00135             {
00136                 message_cb(1, "non-standard number or tracks: %d", tr);
00137             }
00138         }
00139     }
00140 
00141     if(!for_writing)
00142     {
00143         if(stat_ok)
00144         {
00145             if(is_image)
00146             {
00147                 the_file = fopen(name, "rb");
00148                 if(the_file == NULL)
00149                 {
00150                     message_cb(0, "could not open %s", name);
00151                 }
00152                 if(error_info)
00153                 {
00154                     message_cb(1, "image contains error information");
00155                 }
00156                 if(settings->end_track == -1)
00157                 {
00158                     settings->end_track = tr;
00159                 }
00160                 else if(settings->end_track > tr)
00161                 {
00162                     message_cb(1, "resetting end track to %d", tr);
00163                     settings->end_track = tr;
00164                 }
00165                 /* FIXME: error map */
00166             }
00167             else
00168             {
00169                 message_cb(0, "neither a .d64 not .d71 file: %s", name);
00170             }
00171         }
00172         else
00173         {
00174             message_cb(0, "could not stat %s", name);
00175         }
00176     }
00177     else
00178     {
00179         the_file = fopen(name, is_image ? "r+b" : "wb");
00180         if(the_file)
00181         {
00182             /* check whether we must resize or create an image file */
00183             int new_tr;
00184             if(settings->two_sided)
00185             {
00186                 new_tr = D71_TRACKS;
00187             }
00188             else if(settings->end_track <= STD_TRACKS)
00189             {
00190                 new_tr = STD_TRACKS;
00191             }
00192             else if(settings->end_track <= EXT_TRACKS)
00193             {
00194                 new_tr = EXT_TRACKS;
00195             }
00196             else
00197             {
00198                 new_tr = TOT_TRACKS;
00199             }
00200 
00201             /* always use maximum size for error map */
00202             error_map = calloc(D71_BLOCKS, 1);
00203             if(!error_map)
00204             {
00205                 message_cb(0, "no memory for error map");
00206                 fclose(the_file);
00207                 if(!is_image)
00208                 {
00209                     arch_unlink(name);
00210                 }
00211                 return 1;
00212             }
00213 
00214             if(is_image)
00215             {
00216                 if(error_info)
00217                 {
00218                     if(fseek(the_file, block_count * BLOCKSIZE, SEEK_SET) != 0 ||
00219                        fread(error_map, block_count, 1, the_file) != 1)
00220                     {
00221                         message_cb(0, "%s: could not read error map", name);
00222                         fclose(the_file);
00223                         return 1;
00224                     }
00225                 }
00226                 if(fseek(the_file, block_count * BLOCKSIZE, SEEK_SET) != 0)
00227                 {
00228                     message_cb(0, "%s: could not seek to end of file", name);
00229                     fclose(the_file);
00230                     return 1;
00231                 }
00232             }
00233 
00234             if(new_tr > tr)
00235             {
00236                 /* grow image */
00237                 char block[BLOCKSIZE];
00238                 memset(block, '\0', BLOCKSIZE);
00239                 while(tr < new_tr)
00240                 {
00241                     int s;
00242                     s = d64copy_sector_count(settings->two_sided, ++tr);
00243                     if(fwrite(block, BLOCKSIZE, s, the_file) != (size_t)s)
00244                     {
00245                         message_cb(0, "could not write %s", name);
00246                         fclose(the_file);
00247                         if(!is_image)
00248                             arch_unlink(name);
00249                         return 1;
00250                     }
00251                     block_count += s;
00252                 }
00253             }
00254         }
00255         else
00256         {
00257             message_cb(0, "could not open %s", name);
00258         }
00259     }
00260     return the_file == NULL;
00261 }
00262 
00263 static void close_disk(void)
00264 {
00265     int i, has_errors = 0;
00266 
00267     /* if writing the block was interrupted, make sure it is
00268      * redone before closing the disk 
00269      */
00270 
00271     if (the_file && atom_execute)
00272     {
00273         atom_execute = 0;
00274         write_block(atom_tr, atom_se, atom_blk, atom_size, atom_read_status);
00275     }
00276 
00277     if (fs_settings)
00278     {
00279         switch(fs_settings->error_mode)
00280         {
00281             case em_always:
00282                 has_errors = 1;
00283                 break;
00284             case em_never:
00285                 has_errors = 0;
00286                 break;
00287             default:
00288                 if(error_map)
00289                 {
00290                     for(i = 0; !has_errors && i < block_count; i++)
00291                     {
00292                         has_errors = error_map[i] != 0;
00293                     }
00294                 }
00295                 break;
00296         }
00297     }
00298 
00299     if(the_file)
00300     {
00301         if(has_errors)
00302         {
00303             if(fseek(the_file, block_count * BLOCKSIZE, SEEK_SET) == 0)
00304             {
00305                 fwrite(error_map, block_count, 1, the_file);
00306             }
00307         } 
00308         else
00309         {
00310             arch_ftruncate(arch_fileno(the_file), block_count * BLOCKSIZE);
00311         }
00312     }
00313 
00314     if(error_map)
00315     {
00316         free(error_map);
00317         error_map = NULL;
00318     }
00319     if(the_file)
00320     {
00321         fclose(the_file);
00322         the_file = NULL;
00323     }
00324 }
00325 
00326 DECLARE_TRANSFER_FUNCS(fs_transfer, 0, 0);

Generated on Sun Apr 30 18:45:49 2006 for opencbm by  doxygen 1.4.2