DiskDevice.cpp

Go to the documentation of this file.
00001 /* ES40 emulator.
00002  * Copyright (C) 2007-2008 by the ES40 Emulator Project
00003  *
00004  * WWW    : http://sourceforge.net/projects/es40
00005  * E-mail : camiel@camicom.com
00006  * 
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  * 
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  * 
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00020  * 
00021  * Although this is not required, the author would appreciate being notified of, 
00022  * and receiving any modifications you may make to the source code that might serve
00023  * the general public.
00024  */
00025 
00054 #include "StdAfx.h"
00055 #include "DiskDevice.h"
00056 
00057 #if defined(_WIN32)
00058 #include <WinIoCtl.h>
00059 #endif
00060 CDiskDevice::CDiskDevice(CConfigurator*  cfg, CSystem*  sys, CDiskController*  c,
00061                          int idebus, int idedev) : CDisk(cfg, sys, c, idebus, idedev)
00062 {
00063   filename = myCfg->get_text_value("device");
00064   if(!filename)
00065   {
00066     FAILURE_1(Configuration, "%s: Disk has no device attached!\n", devid_string);
00067   }
00068 
00069   if(read_only)
00070   {
00071 #if defined(_WIN32)
00072     buffer = (char*) malloc(2048);
00073     buffer_size = 2048;
00074     handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
00075                         OPEN_EXISTING,
00076                         FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL);
00077 #else
00078     handle = fopen(filename, "rb");
00079 #endif
00080   }
00081   else
00082   {
00083 #if defined(_WIN32)
00084     handle = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
00085                         NULL, OPEN_EXISTING,
00086                         FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL);
00087 #else
00088     handle = fopen(filename, "rb+");
00089 #endif
00090   }
00091 
00092 #if defined(_WIN32)
00093   if(handle == INVALID_HANDLE_VALUE)
00094   {
00095     FAILURE_3(Runtime, "%s: Could not open device %s. Error %ld.", devid_string,
00096               filename, GetLastError());
00097   }
00098 
00099 #else
00100   if(!handle)
00101   {
00102     FAILURE_2(Runtime, "%s: Could not open device %s.", devid_string, filename);
00103   }
00104 #endif
00105 
00106   // determine size...
00107 #if defined(_WIN32)
00108   DISK_GEOMETRY x;
00109   DWORD         bytesret;
00110 
00111   if(!DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &x,
00112      sizeof(x), &bytesret, NULL))
00113   {
00114     FAILURE_3(Runtime, "%s: Could not get drive geometry for %s. Error %ld.",
00115               devid_string, filename, GetLastError());
00116   }
00117 
00118   sectors = x.SectorsPerTrack;
00119   heads = x.TracksPerCylinder;
00120   byte_size = x.Cylinders.QuadPart *
00121     x.TracksPerCylinder *
00122     x.SectorsPerTrack *
00123     x.BytesPerSector;
00124   dev_block_size = x.BytesPerSector;
00125 
00126   LARGE_INTEGER a;
00127   a.QuadPart = 0;
00128   SetFilePointerEx(handle, a, (PLARGE_INTEGER) & state.byte_pos, FILE_BEGIN);
00129 #else
00130   fseek_large(handle, 0, SEEK_END);
00131   byte_size = ftell_large(handle);
00132   fseek_large(handle, 0, SEEK_SET);
00133   state.byte_pos = ftell_large(handle);
00134 
00135   sectors = 32;
00136   heads = 8;
00137 #endif
00138 
00139   //calc_cylinders();
00140   determine_layout();
00141 
00142   model_number = myCfg->get_text_value("model_number", filename);
00143 
00144   printf("%s: Mounted device %s, %"LL "d %d-byte blocks, %"LL "d/%d/%d.\n",
00145          devid_string, filename, byte_size / state.block_size, state.block_size,
00146          cylinders, heads, sectors);
00147 }
00148 
00149 CDiskDevice::~CDiskDevice(void)
00150 {
00151   printf("%s: Closing file.\n", devid_string);
00152 #if defined(_WIN32)
00153   if(handle != INVALID_HANDLE_VALUE)
00154     CloseHandle(handle);
00155 #else
00156   if(handle)
00157     fclose(handle);
00158 #endif
00159 }
00160 
00161 bool CDiskDevice::seek_byte(off_t_large byte)
00162 {
00163   if(byte >= byte_size)
00164   {
00165     FAILURE_1(InvalidArgument, "%s: Seek beyond end of file!\n", devid_string);
00166   }
00167 
00168 #if defined(_WIN32)
00169   state.byte_pos = byte;
00170 #else
00171   fseek_large(handle, byte, SEEK_SET);
00172   state.byte_pos = ftell_large(handle);
00173 #endif
00174   return true;
00175 }
00176 
00177 size_t CDiskDevice::read_bytes(void* dest, size_t bytes)
00178 {
00179 
00180   //  printf("%s: read %d bytes @ %" LL "d.\n",devid_string,bytes,state.byte_pos);
00181 #if defined(_WIN32)
00182   off_t_large   byte_from = (state.byte_pos / dev_block_size) * dev_block_size;
00183   off_t_large   byte_to =
00184       (
00185         ((state.byte_pos + bytes - 1) / dev_block_size) +
00186         1
00187       ) *
00188       dev_block_size;
00189   DWORD         byte_len = (DWORD) (byte_to - byte_from);
00190   DWORD         byte_off = (DWORD) (state.byte_pos - byte_from);
00191   LARGE_INTEGER a;
00192   DWORD         r;
00193 
00194   if(byte_len > buffer_size)
00195   {
00196     buffer_size = byte_len;
00197     CHECK_REALLOCATION(buffer, realloc(buffer, buffer_size), char);
00198 
00199     //    printf("%s: buffer enlarged to %d bytes.\n",devid_string,buffer_size);
00200   }
00201 
00202   a.QuadPart = byte_from;
00203   SetFilePointerEx(handle, a, NULL, FILE_BEGIN);
00204 
00205   ReadFile(handle, buffer, byte_len, &r, NULL);
00206 
00207   if(r != (byte_len))
00208   {
00209     printf("%s: Tried to read %d bytes from pos %"LL
00210              "d, but could only read %d bytes!\n", devid_string, byte_len,
00211            byte_from, r);
00212     printf("%s: Error %ld.\n", devid_string, GetLastError());
00213   }
00214 
00215   memcpy(dest, buffer + byte_off, bytes);
00216   state.byte_pos += bytes;
00217   return bytes;
00218 #else
00219   size_t  r;
00220   r = fread(dest, 1, bytes, handle);
00221   state.byte_pos = ftell_large(handle);
00222   return r;
00223 #endif
00224 }
00225 
00226 size_t CDiskDevice::write_bytes(void* src, size_t bytes)
00227 {
00228   if(read_only)
00229     return 0;
00230 
00231 #if defined(_WIN32)
00232   off_t_large   byte_from = (state.byte_pos / dev_block_size) * dev_block_size;
00233   off_t_large   byte_to =
00234       (
00235         ((state.byte_pos + bytes - 1) / dev_block_size) +
00236         1
00237       ) *
00238       dev_block_size;
00239   DWORD         byte_len = (DWORD) (byte_to - byte_from);
00240   DWORD         byte_off = (DWORD) (state.byte_pos - byte_from);
00241   LARGE_INTEGER a;
00242   DWORD         r;
00243 
00244   if(byte_len > buffer_size)
00245   {
00246     buffer_size = byte_len;
00247     CHECK_REALLOCATION(buffer, realloc(buffer, buffer_size), char);
00248   }
00249 
00250   if(byte_from != state.byte_pos)
00251   {
00252 
00253     // we don't write the entire first block, so we read it
00254     // from disk first so we don't corrupt the disk
00255     a.QuadPart = byte_from;
00256     SetFilePointerEx(handle, a, NULL, FILE_BEGIN);
00257     ReadFile(handle, buffer, (DWORD) dev_block_size, &r, NULL);
00258     if(r != (dev_block_size))
00259     {
00260       printf("%s: Tried to read %d bytes from pos %"LL
00261                "d, but could only read %d bytes!\n", devid_string,
00262              dev_block_size, byte_from, r);
00263       FAILURE(InvalidArgument,
00264               "Error during device write operation. Terminating to avoid disk corruption.");
00265     }
00266   }
00267 
00268   if((byte_to != state.byte_pos + bytes) && (byte_to - byte_from > dev_block_size))
00269   {
00270 
00271     // we don't write the entire last block, so we read it
00272     // from disk first so we don't corrupt the disk
00273     a.QuadPart = byte_to - dev_block_size;
00274     SetFilePointerEx(handle, a, NULL, FILE_BEGIN);
00275     ReadFile(handle, buffer + byte_len - dev_block_size, (DWORD) dev_block_size,
00276              &r, NULL);
00277     if(r != (dev_block_size))
00278     {
00279       printf("%s: Tried to read %d bytes from pos %"LL
00280                "d, but could only read %d bytes!\n", devid_string,
00281              dev_block_size, byte_to - dev_block_size, r);
00282       FAILURE(InvalidArgument,
00283               "Error during device write operation. Terminating to avoid disk corruption.");
00284     }
00285   }
00286 
00287   // add the data we're writing to the buffer
00288   memcpy(buffer + byte_off, src, bytes);
00289 
00290   a.QuadPart = byte_from;
00291   SetFilePointerEx(handle, a, NULL, FILE_BEGIN);
00292 
00293   // and write the buffer to disk
00294   WriteFile(handle, buffer, byte_len, &r, NULL);
00295 
00296   if(r != byte_len)
00297   {
00298     printf("%s: Tried to write %d bytes to pos %"LL
00299              "d, but could only write %d bytes!\n", devid_string, byte_len,
00300            byte_from, r);
00301     FAILURE(InvalidArgument,
00302             "Error during device write operation. Terminating to avoid disk corruption.");
00303   }
00304 
00305   state.byte_pos += bytes;
00306   return bytes;
00307 #else
00308   size_t  r;
00309   r = fwrite(src, 1, bytes, handle);
00310   state.byte_pos = ftell_large(handle);
00311   return r;
00312 #endif
00313 }

SourceForge.net Logo
Project space on SourceForge.net