00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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
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
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
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
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
00254
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
00272
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
00288 memcpy(buffer + byte_off, src, bytes);
00289
00290 a.QuadPart = byte_from;
00291 SetFilePointerEx(handle, a, NULL, FILE_BEGIN);
00292
00293
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 }