1 /**
2 * UAE - The Un*x Amiga Emulator
3 *
4 * Hardfile emulation for *nix systems
5 *
6 * Copyright 2003-2006 Richard Drummond
7 * Copyright 2008-2010 Mustafa TUFAN
8 * Based on hardfile_win32.c
9 */
10
11 #include "sysconfig.h"
12 #include "sysdeps.h"
13
14 #include "options.h"
15 #include "filesys.h"
16 #include "zfile.h"
17 #include "uae/fs.h"
18 #include "uae/io.h"
19 #include "uae/log.h"
20
21 #ifdef MACOSX
22 #include <sys/stat.h>
23 #include <sys/disk.h>
24 #endif
25
26 #ifdef OPENBSD
27 #include <sys/types.h>
28 #include <sys/disklabel.h>
29 #include <sys/dkio.h>
30 #include <sys/ioctl.h>
31 #include <fcntl.h>
32 #endif
33
34 #define hfd_log write_log
35 static int g_debug = 0;
36
37 //#define HDF_DEBUG
38 #ifdef HDF_DEBUG
39 #define DEBUG_LOG write_log ( "%s: ", __func__); write_log
40 #else
41 #define DEBUG_LOG(...) do ; while(0)
42 #endif
43
44 struct hardfilehandle
45 {
46 int zfile;
47 struct zfile *zf;
48 FILE *h;
49 };
50
51 struct uae_driveinfo {
52 char vendor_id[128];
53 char product_id[128];
54 char product_rev[128];
55 char product_serial[128];
56 char device_name[2048];
57 char device_path[2048];
58 uae_u64 size;
59 uae_u64 offset;
60 int bytespersector;
61 int removablemedia;
62 int nomedia;
63 int dangerous;
64 int readonly;
65 };
66
67 #define HDF_HANDLE_WIN32 1
68 #define HDF_HANDLE_ZFILE 2
69 #define HDF_HANDLE_LINUX 3
70 #undef INVALID_HANDLE_VALUE
71 #define INVALID_HANDLE_VALUE NULL
72
73 #define CACHE_SIZE 16384
74 #define CACHE_FLUSH_TIME 5
75
76 /* safety check: only accept drives that:
77 * - contain RDSK in block 0
78 * - block 0 is zeroed
79 */
80
81 int harddrive_dangerous, do_rdbdump;
82 static struct uae_driveinfo uae_drives[MAX_FILESYSTEM_UNITS];
83
rdbdump(FILE * h,uae_u64 offset,uae_u8 * buf,int blocksize)84 static void rdbdump (FILE *h, uae_u64 offset, uae_u8 *buf, int blocksize)
85 {
86 static int cnt = 1;
87 int i, blocks;
88 char name[100];
89 FILE *f;
90
91 blocks = (buf[132] << 24) | (buf[133] << 16) | (buf[134] << 8) | (buf[135] << 0);
92 if (blocks < 0 || blocks > 100000)
93 return;
94 _stprintf (name, "rdb_dump_%d.rdb", cnt);
95 f = uae_tfopen (name, "wb");
96 if (!f)
97 return;
98 for (i = 0; i <= blocks; i++) {
99 if (uae_fseeko64 (h, offset, SEEK_SET) != 0)
100 break;
101 int outlen = fread (buf, 1, blocksize, h);
102 if (outlen != blocksize) {
103 write_log("rdbdump: warning: read %d bytes (not blocksize %d)\n",
104 outlen, blocksize);
105 }
106 fwrite (buf, 1, blocksize, f);
107 offset += blocksize;
108 }
109 fclose (f);
110 cnt++;
111 }
112
113 //static int ismounted (int hd)
114 //FIXME:
ismounted(FILE * f)115 static int ismounted (FILE* f) {
116 STUB("");
117 int mounted;
118 //mounted = 1;
119 mounted = 0;
120 return mounted;
121 }
122
123 #define CA "Commodore\0Amiga\0"
safetycheck(FILE * h,const char * name,uae_u64 offset,uae_u8 * buf,int blocksize)124 static int safetycheck (FILE *h, const char *name, uae_u64 offset, uae_u8 *buf, int blocksize)
125 {
126 int i, j, blocks = 63, empty = 1;
127 long outlen;
128
129 for (j = 0; j < blocks; j++) {
130 if (uae_fseeko64 (h, offset, SEEK_SET) != 0) {
131 write_log ("hd ignored, SetFilePointer failed, error %d\n", errno);
132 return 1;
133 }
134 memset (buf, 0xaa, blocksize);
135 outlen = fread (buf, 1, blocksize, h);
136 if (outlen != blocksize) {
137 write_log ("hd ignored, read error %d!\n", errno);
138 return 2;
139 }
140 if (j == 0 && offset > 0)
141 return -5;
142 if (j == 0 && buf[0] == 0x39 && buf[1] == 0x10 && buf[2] == 0xd3 && buf[3] == 0x12) {
143 // ADIDE "CPRM" hidden block..
144 if (do_rdbdump)
145 rdbdump (h, offset, buf, blocksize);
146 write_log ("hd accepted (adide rdb detected at block %d)\n", j);
147 return -3;
148 }
149 if (!memcmp (buf, "RDSK", 4) || !memcmp (buf, "DRKS", 4)) {
150 if (do_rdbdump)
151 rdbdump (h, offset, buf, blocksize);
152 write_log ("hd accepted (rdb detected at block %d)\n", j);
153 return -1;
154 }
155
156 if (!memcmp (buf + 2, "CIS@", 4) && !memcmp (buf + 16, CA, strlen (CA))) {
157 write_log ("hd accepted (PCMCIA RAM)\n");
158 return -2;
159 }
160 if (j == 0) {
161 for (i = 0; i < blocksize; i++) {
162 if (buf[i])
163 empty = 0;
164 }
165 }
166 offset += blocksize;
167 }
168 if (!empty) {
169 int mounted;
170 mounted = ismounted (h);
171 if (!mounted) {
172 write_log ("hd accepted, not empty and not mounted in Windows\n");
173 return -8;
174 }
175 if (mounted < 0) {
176 write_log ("hd ignored, NTFS partitions\n");
177 return 0;
178 }
179 if (harddrive_dangerous == 0x1234dead)
180 return -6;
181 write_log ("hd ignored, not empty and no RDB detected or Windows mounted\n");
182 return 0;
183 }
184 write_log ("hd accepted (empty)\n");
185 return -9;
186 }
187
188 /*
189 static void trim (TCHAR *s)
190 {
191 while(_tcslen(s) > 0 && s[_tcslen(s) - 1] == ' ') {
192 s[_tcslen(s) - 1] = 0;
193 }
194 }
195 */
196
isharddrive(const TCHAR * name)197 static int isharddrive (const TCHAR *name)
198 {
199 int i;
200
201 for (i = 0; i < hdf_getnumharddrives (); i++) {
202 if (!_tcscmp (uae_drives[i].device_name, name))
203 return i;
204 }
205 return -1;
206 }
207
208 static const char *hdz[] = { "hdz", "zip", "rar", "7z", NULL };
209
hdf_open_target(struct hardfiledata * hfd,const char * pname)210 int hdf_open_target (struct hardfiledata *hfd, const char *pname)
211 {
212 FILE *h = INVALID_HANDLE_VALUE;
213 int i;
214 struct uae_driveinfo *udi;
215 char *name = strdup (pname);
216
217 if (getenv("FS_DEBUG_HDF")) {
218 g_debug = 1;
219 }
220 if (g_debug) {
221 write_log("\n\n-- hdf_open_target pname = %s\n", pname);
222 }
223
224 hfd->flags = 0;
225 hfd->drive_empty = 0;
226 hdf_close (hfd);
227 hfd->cache = (uae_u8*)xmalloc (uae_u8, CACHE_SIZE);
228 hfd->cache_valid = 0;
229 hfd->virtual_size = 0;
230 hfd->virtual_rdb = NULL;
231 if (!hfd->cache) {
232 write_log ("VirtualAlloc(%d) failed, error %d\n", CACHE_SIZE, errno);
233 goto end;
234 }
235 hfd->handle = xcalloc (struct hardfilehandle, 1);
236 hfd->handle->h = INVALID_HANDLE_VALUE;
237 hfd_log ("hfd open: '%s'\n", name);
238 if (_tcslen (name) > 4 && !_tcsncmp (name,"HD_", 3)) {
239 hdf_init_target ();
240 i = isharddrive (name);
241 if (i >= 0) {
242 udi = &uae_drives[i];
243 hfd->flags = HFD_FLAGS_REALDRIVE;
244 if (udi->nomedia)
245 hfd->drive_empty = -1;
246 if (udi->readonly)
247 hfd->ci.readonly = 1;
248 h = uae_tfopen (udi->device_path, hfd->ci.readonly ? "rb" : "r+b");
249 hfd->handle->h = h;
250 if (h == INVALID_HANDLE_VALUE)
251 goto end;
252 _tcsncpy (hfd->vendor_id, udi->vendor_id, 8);
253 _tcsncpy (hfd->product_id, udi->product_id, 16);
254 _tcsncpy (hfd->product_rev, udi->product_rev, 4);
255 hfd->offset = udi->offset;
256 hfd->physsize = hfd->virtsize = udi->size;
257 hfd->ci.blocksize = udi->bytespersector;
258 if (hfd->offset == 0 && !hfd->drive_empty) {
259 int sf = safetycheck (hfd->handle->h, udi->device_path, 0, hfd->cache, hfd->ci.blocksize);
260 if (sf > 0)
261 goto end;
262 if (sf == 0 && !hfd->ci.readonly && harddrive_dangerous != 0x1234dead) {
263 write_log ("'%s' forced read-only, safetycheck enabled\n", udi->device_path);
264 hfd->dangerous = 1;
265 // clear GENERIC_WRITE
266 fclose (h);
267 h = uae_tfopen (udi->device_path, "r+b");
268 hfd->handle->h = h;
269 if (h == INVALID_HANDLE_VALUE)
270 goto end;
271 }
272 }
273 hfd->handle_valid = HDF_HANDLE_LINUX;
274 hfd->emptyname = strdup (name);
275 } else {
276 hfd->flags = HFD_FLAGS_REALDRIVE;
277 hfd->drive_empty = -1;
278 hfd->emptyname = strdup (name);
279 }
280 } else {
281 int zmode = 0;
282 char *ext = _tcsrchr (name, '.');
283 if (ext != NULL) {
284 ext++;
285 for (i = 0; hdz[i]; i++) {
286 if (!_tcsicmp (ext, hdz[i]))
287 zmode = 1;
288 }
289 }
290 h = uae_tfopen (name, hfd->ci.readonly ? "rb" : "r+b");
291 if (h == INVALID_HANDLE_VALUE)
292 goto end;
293 hfd->handle->h = h;
294 i = _tcslen (name) - 1;
295 while (i >= 0) {
296 if ((i > 0 && (name[i - 1] == '/' || name[i - 1] == '\\')) || i == 0) {
297 _tcscpy (hfd->vendor_id, "UAE");
298 _tcsncpy (hfd->product_id, name + i, 15);
299 _tcscpy (hfd->product_rev, "0.3");
300 break;
301 }
302 i--;
303 }
304 if (h != INVALID_HANDLE_VALUE) {
305 // determine size of hdf file
306 int ret;
307 off_t low = -1;
308
309 #if defined(MACOSX) || defined(OPENBSD)
310 // check type of file
311 struct stat st;
312 ret = stat(name,&st);
313 if (ret) {
314 write_log("osx: can't stat '%s'\n", name);
315 goto end;
316 }
317 // block devices need special handling on BSD and OSX
318 if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)) {
319 int fh = fileno(h);
320 #if defined(MACOSX)
321 uint32_t block_size;
322 uint64_t block_count;
323 // get number of blocks
324 ret = ioctl(fh, DKIOCGETBLOCKCOUNT, &block_count);
325 if (ret) {
326 write_log("osx: can't get block count of '%s' (%d)\n",
327 name, fh);
328 goto end;
329 }
330 // get block size
331 ret = ioctl(fh, DKIOCGETBLOCKSIZE, &block_size);
332 if (ret) {
333 write_log("osx: can't get block size of '%s' (%d)\n",
334 name, fh);
335 goto end;
336 }
337 write_log("osx: found raw device: block_size=%u "
338 "block_count=%llu\n", block_size, block_count);
339 low = block_size * block_count;
340 #elif defined(OPENBSD)
341 struct disklabel label;
342 if (ioctl(fh, DIOCGDINFO, &label) < 0) {
343 write_log("openbsd: can't get disklabel of '%s' (%d)\n", name, fh);
344 goto end;
345 }
346 write_log("openbsd: bytes per sector: %u\n", label.d_secsize);
347 write_log("openbsd: sectors per unit: %u\n", label.d_secperunit);
348 low = label.d_secsize * label.d_secperunit;
349 write_log("openbsd: total bytes: %llu\n", low);
350 #endif
351 }
352 #endif // OPENBSD || MACOSX
353
354 if (low == -1) {
355 // assuming regular file; seek to end and ftell
356 ret = uae_fseeko64 (h, 0, SEEK_END);
357 if (ret)
358 goto end;
359 low = uae_ftello64 (h);
360 if (low == -1)
361 goto end;
362 }
363
364 low &= ~(hfd->ci.blocksize - 1);
365 hfd->physsize = hfd->virtsize = low;
366 if (g_debug) {
367 write_log("set physsize = virtsize = %lld (low)\n",
368 hfd->virtsize);
369 }
370 hfd->handle_valid = HDF_HANDLE_LINUX;
371 if (hfd->physsize < 64 * 1024 * 1024 && zmode) {
372 write_log ("HDF '%s' re-opened in zfile-mode\n", name);
373 fclose (h);
374 hfd->handle->h = INVALID_HANDLE_VALUE;
375 hfd->handle->zf = zfile_fopen(name, hfd->ci.readonly ? "rb" : "r+b", ZFD_NORMAL);
376 hfd->handle->zfile = 1;
377 if (!h)
378 goto end;
379 zfile_fseek (hfd->handle->zf, 0, SEEK_END);
380 hfd->physsize = hfd->virtsize = zfile_ftell (hfd->handle->zf);
381 if (g_debug) {
382 write_log("set physsize = virtsize = %lld\n",
383 hfd->virtsize);
384 }
385 zfile_fseek (hfd->handle->zf, 0, SEEK_SET);
386 hfd->handle_valid = HDF_HANDLE_ZFILE;
387 }
388 } else {
389 write_log ("HDF '%s' failed to open. error = %d\n", name, errno);
390 }
391 }
392 if (hfd->handle_valid || hfd->drive_empty) {
393 hfd_log ("HDF '%s' opened, size=%dK mode=%d empty=%d\n",
394 name, (int) (hfd->physsize / 1024), hfd->handle_valid, hfd->drive_empty);
395 return 1;
396 }
397 end:
398 hdf_close (hfd);
399 xfree (name);
400 return 0;
401 }
402
403 /*
404 static void freehandle (struct hardfilehandle *h)
405 {
406 if (!h)
407 return;
408 if (!h->zfile && h->h != INVALID_HANDLE_VALUE)
409 fclose (h->h);
410 if (h->zfile && h->zf)
411 zfile_fclose (h->zf);
412 h->zf = NULL;
413 h->h = INVALID_HANDLE_VALUE;
414 h->zfile = 0;
415 }
416 */
417
hdf_close_target(struct hardfiledata * hfd)418 void hdf_close_target (struct hardfiledata *hfd) {
419 write_log("hdf_close_target\n");
420 if (hfd->handle && hfd->handle->h) {
421 write_log("closing file handle %p\n", hfd->handle->h);
422 fclose(hfd->handle->h);
423 }
424 //freehandle (hfd->handle);
425 xfree (hfd->handle);
426 xfree (hfd->emptyname);
427 hfd->emptyname = NULL;
428 hfd->handle = NULL;
429 hfd->handle_valid = 0;
430 if (hfd->cache)
431 xfree (hfd->cache);
432 xfree(hfd->virtual_rdb);
433 hfd->virtual_rdb = 0;
434 hfd->virtual_size = 0;
435 hfd->cache = 0;
436 hfd->cache_valid = 0;
437 hfd->drive_empty = 0;
438 hfd->dangerous = 0;
439 }
440
hdf_dup_target(struct hardfiledata * dhfd,const struct hardfiledata * shfd)441 int hdf_dup_target (struct hardfiledata *dhfd, const struct hardfiledata *shfd)
442 {
443 if (!shfd->handle_valid)
444 return 0;
445
446 return 0;
447 }
448
hdf_seek(struct hardfiledata * hfd,uae_u64 offset)449 static int hdf_seek (struct hardfiledata *hfd, uae_u64 offset)
450 {
451 size_t ret;
452
453 if (hfd->handle_valid == 0) {
454 gui_message ("hd: hdf handle is not valid. bug.");
455 abort();
456 }
457 if (offset >= hfd->physsize - hfd->virtual_size) {
458 gui_message ("hd: tried to seek out of bounds! (0x%llx >= 0x%llx)\n", offset, hfd->physsize);
459 abort ();
460 }
461 offset += hfd->offset;
462 if (offset & (hfd->ci.blocksize - 1)) {
463 gui_message ("hd: poscheck failed, offset=0x%llx not aligned to blocksize=%d! (0x%llx & 0x%04.4x = 0x%04.4x)\n",
464 offset, hfd->ci.blocksize, offset, hfd->ci.blocksize, offset & (hfd->ci.blocksize - 1));
465 abort ();
466 }
467 if (hfd->handle_valid == HDF_HANDLE_LINUX) {
468 ret = uae_fseeko64 (hfd->handle->h, offset, SEEK_SET);
469 if (ret) {
470 write_log("hdf_seek failed\n");
471 return -1;
472 }
473 } else if (hfd->handle_valid == HDF_HANDLE_ZFILE) {
474 zfile_fseek (hfd->handle->zf, (long)offset, SEEK_SET);
475 }
476 return 0;
477 }
478
poscheck(struct hardfiledata * hfd,int len)479 static void poscheck (struct hardfiledata *hfd, int len)
480 {
481 int ret;
482 uae_u64 pos = 0;
483
484 if (hfd->handle_valid == HDF_HANDLE_LINUX) {
485 ret = uae_fseeko64 (hfd->handle->h, 0, SEEK_CUR);
486 if (ret) {
487 gui_message ("hd: poscheck failed. seek failure, ret %d", ret);
488 abort ();
489 }
490 pos = uae_ftello64 (hfd->handle->h);
491 } else if (hfd->handle_valid == HDF_HANDLE_ZFILE) {
492 pos = zfile_ftell (hfd->handle->zf);
493 }
494 if (len < 0) {
495 gui_message ("hd: poscheck failed, negative length! (%d)", len);
496 abort ();
497 }
498 if (pos < hfd->offset) {
499 gui_message ("hd: poscheck failed, offset out of bounds! (0x%llx < 0x%llx)", pos, hfd->offset);
500 abort ();
501 }
502 if (pos >= hfd->offset + hfd->physsize - hfd->virtual_size || pos >= hfd->offset + hfd->physsize + len - hfd->virtual_size) {
503 gui_message ("hd: poscheck failed, offset out of bounds! (0x%llx >= 0x%llx, LEN=%d)", pos, hfd->offset + hfd->physsize, len);
504 abort ();
505 }
506 if (pos & (hfd->ci.blocksize - 1)) {
507 gui_message ("hd: poscheck failed, offset not aligned to blocksize! (0x%llx & 0x%04.4x = 0x%04.4x\n", pos, hfd->ci.blocksize, pos & hfd->ci.blocksize);
508 abort ();
509 }
510 }
511
isincache(struct hardfiledata * hfd,uae_u64 offset,int len)512 static int isincache (struct hardfiledata *hfd, uae_u64 offset, int len)
513 {
514 if (!hfd->cache_valid)
515 return -1;
516 if (offset >= hfd->cache_offset && offset + len <= hfd->cache_offset + CACHE_SIZE)
517 return (int)(offset - hfd->cache_offset);
518 return -1;
519 }
520
521 #if 0
522 void hfd_flush_cache (struct hardfiledata *hfd, int now)
523 {
524 DWORD outlen = 0;
525 if (!hfd->cache_needs_flush || !hfd->cache_valid)
526 return;
527 if (now || time (NULL) > hfd->cache_needs_flush + CACHE_FLUSH_TIME) {
528 hdf_log ("flushed %d %d %d\n", now, time(NULL), hfd->cache_needs_flush);
529 hdf_seek (hfd, hfd->cache_offset);
530 poscheck (hfd, CACHE_SIZE);
531 WriteFile (hfd->handle, hfd->cache, CACHE_SIZE, &outlen, NULL);
532 hfd->cache_needs_flush = 0;
533 }
534 }
535 #endif
536
hdf_read_2(struct hardfiledata * hfd,void * buffer,uae_u64 offset,int len)537 static int hdf_read_2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
538 {
539 long outlen = 0;
540 int coffset;
541
542 if (offset == 0)
543 hfd->cache_valid = 0;
544 coffset = isincache (hfd, offset, len);
545 if (coffset >= 0) {
546 memcpy (buffer, hfd->cache + coffset, len);
547 return len;
548 }
549 hfd->cache_offset = offset;
550 if (offset + CACHE_SIZE > hfd->offset + (hfd->physsize - hfd->virtual_size))
551 hfd->cache_offset = hfd->offset + (hfd->physsize - hfd->virtual_size) - CACHE_SIZE;
552 hdf_seek (hfd, hfd->cache_offset);
553 poscheck (hfd, CACHE_SIZE);
554 if (hfd->handle_valid == HDF_HANDLE_LINUX)
555 outlen = fread (hfd->cache, 1, CACHE_SIZE, hfd->handle->h);
556 else if (hfd->handle_valid == HDF_HANDLE_ZFILE)
557 outlen = zfile_fread (hfd->cache, 1, CACHE_SIZE, hfd->handle->zf);
558 hfd->cache_valid = 0;
559 if (outlen != CACHE_SIZE)
560 return 0;
561 hfd->cache_valid = 1;
562 coffset = isincache (hfd, offset, len);
563 if (coffset >= 0) {
564 memcpy (buffer, hfd->cache + coffset, len);
565 return len;
566 }
567 write_log ("hdf_read: cache bug! offset=0x%llx len=%d\n", offset, len);
568 hfd->cache_valid = 0;
569 return 0;
570 }
571
hdf_read_target(struct hardfiledata * hfd,void * buffer,uae_u64 offset,int len)572 int hdf_read_target (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
573 {
574 int got = 0;
575 uae_u8 *p = (uae_u8*)buffer;
576
577 if (hfd->drive_empty)
578 return 0;
579 if (offset < hfd->virtual_size) {
580 uae_u64 len2 = offset + len <= hfd->virtual_size ? len : hfd->virtual_size - offset;
581 if (!hfd->virtual_rdb)
582 return 0;
583 memcpy (buffer, hfd->virtual_rdb + offset, len2);
584 return len2;
585 }
586 offset -= hfd->virtual_size;
587 while (len > 0) {
588 int maxlen;
589 int ret = 0;
590 if (hfd->physsize < CACHE_SIZE) {
591 hfd->cache_valid = 0;
592 hdf_seek (hfd, offset);
593 poscheck (hfd, len);
594 if (hfd->handle_valid == HDF_HANDLE_LINUX) {
595 ret = fread (hfd->cache, 1, len, hfd->handle->h);
596 memcpy (buffer, hfd->cache, ret);
597 } else if (hfd->handle_valid == HDF_HANDLE_ZFILE) {
598 ret = zfile_fread (buffer, 1, len, hfd->handle->zf);
599 }
600 maxlen = len;
601 } else {
602 maxlen = len > CACHE_SIZE ? CACHE_SIZE : len;
603 ret = hdf_read_2 (hfd, p, offset, maxlen);
604 }
605 got += ret;
606 if (ret != maxlen)
607 return got;
608 offset += maxlen;
609 p += maxlen;
610 len -= maxlen;
611 }
612 return got;
613 }
614
hdf_write_2(struct hardfiledata * hfd,void * buffer,uae_u64 offset,int len)615 static int hdf_write_2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
616 {
617 int outlen = 0;
618
619 if (hfd->ci.readonly) {
620 if (g_debug) {
621 write_log("hfd->readonly\n");
622 }
623 return 0;
624 }
625 if (hfd->dangerous) {
626 if (g_debug) {
627 write_log("hfd->dangerous\n");
628 }
629 return 0;
630 }
631 hfd->cache_valid = 0;
632 hdf_seek (hfd, offset);
633 poscheck (hfd, len);
634 memcpy (hfd->cache, buffer, len);
635 if (hfd->handle_valid == HDF_HANDLE_LINUX) {
636 outlen = fwrite (hfd->cache, 1, len, hfd->handle->h);
637 //fflush(hfd->handle->h);
638 if (g_debug) {
639 write_log("wrote %u bytes (wanted %d) at offset %llx\n", outlen,
640 len, offset);
641 }
642 const TCHAR *name = hfd->emptyname == NULL ? _T("<unknown>") : hfd->emptyname;
643 if (offset == 0) {
644 long outlen2;
645 uae_u8 *tmp;
646 int tmplen = 512;
647 tmp = (uae_u8*)xmalloc (uae_u8, tmplen);
648 if (tmp) {
649 memset (tmp, 0xa1, tmplen);
650 hdf_seek (hfd, offset);
651 outlen2 = fread (tmp, 1, tmplen, hfd->handle->h);
652 if (memcmp (hfd->cache, tmp, tmplen) != 0 || outlen != len)
653 gui_message (_T("\"%s\"\n\nblock zero write failed!"), name);
654 xfree (tmp);
655 }
656 }
657 } else if (hfd->handle_valid == HDF_HANDLE_ZFILE) {
658 outlen = zfile_fwrite (hfd->cache, 1, len, hfd->handle->zf);
659 }
660 return outlen;
661 }
hdf_write_target(struct hardfiledata * hfd,void * buffer,uae_u64 offset,int len)662 int hdf_write_target (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
663 {
664 int got = 0;
665 uae_u8 *p = (uae_u8*)buffer;
666
667 if (g_debug) {
668 write_log("hdf_write_target off %llx len %d virtual size %lld\n",
669 offset, len, hfd->virtual_size);
670 }
671 if (hfd->drive_empty) {
672 if (g_debug) {
673 write_log("hfd->drive_empty\n");
674 }
675 return 0;
676 }
677 if (offset < hfd->virtual_size) {
678 if (g_debug) {
679 write_log("offset < hfd->virtual_size\n");
680 }
681 return len;
682 }
683 offset -= hfd->virtual_size;
684 while (len > 0) {
685 int maxlen = len > CACHE_SIZE ? CACHE_SIZE : len;
686 int ret = hdf_write_2 (hfd, p, offset, maxlen);
687 if (ret < 0)
688 return ret;
689 got += ret;
690 if (ret != maxlen)
691 return got;
692 offset += maxlen;
693 p += maxlen;
694 len -= maxlen;
695 }
696 return got;
697 }
698
hdf_resize_target(struct hardfiledata * hfd,uae_u64 newsize)699 int hdf_resize_target(struct hardfiledata *hfd, uae_u64 newsize)
700 {
701 if (newsize < hfd->physsize) {
702 uae_log("hdf_resize_target: truncation not implemented\n");
703 return 0;
704 }
705 if (newsize == hfd->physsize) {
706 return 1;
707 }
708 /* Now, newsize must be larger than hfd->physsize, we seek to newsize - 1
709 * and write a single 0 byte to make the file exactly newsize bytes big. */
710 if (uae_fseeko64(hfd->handle->h, newsize - 1, SEEK_SET) != 0) {
711 uae_log("hdf_resize_target: fseek failed errno %d\n", errno);
712 return 0;
713 }
714 if (fwrite("", 1, 1, hfd->handle->h) != 1) {
715 uae_log("hdf_resize_target: failed to write byte at position "
716 "%lld errno %d\n", newsize - 1, errno);
717 return 0;
718 }
719 uae_log("hdf_resize_target: %lld -> %lld\n", hfd->physsize, newsize);
720 hfd->physsize = newsize;
721 return 1;
722 }
723
724 static int num_drives;
725
hdf_init2(int force)726 static int hdf_init2 (int force)
727 {
728 static int done;
729
730 if (done && !force)
731 return num_drives;
732 done = 1;
733 num_drives = 0;
734 return num_drives;
735 }
736
hdf_init_target(void)737 int hdf_init_target (void) {
738 return hdf_init2 (0);
739 }
740
hdf_getnumharddrives(void)741 int hdf_getnumharddrives (void)
742 {
743 return num_drives;
744 }
745
hdf_getnameharddrive(int index,int flags,int * sectorsize,int * dangerousdrive)746 TCHAR *hdf_getnameharddrive (int index, int flags, int *sectorsize, int *dangerousdrive)
747 {
748 static char name[512];
749 char tmp[32];
750 uae_u64 size = uae_drives[index].size;
751 int nomedia = uae_drives[index].nomedia;
752 const char *dang = "?";
753 const char *rw = "RW";
754
755 if (dangerousdrive)
756 *dangerousdrive = 0;
757 switch (uae_drives[index].dangerous)
758 {
759 case -5:
760 dang = "[PART]";
761 break;
762 case -6:
763 dang = "[MBR]";
764 break;
765 case -7:
766 dang = "[!]";
767 break;
768 case -8:
769 dang = "[UNK]";
770 break;
771 case -9:
772 dang = "[EMPTY]";
773 break;
774 case -3:
775 dang = "(CPRM)";
776 break;
777 case -2:
778 dang = "(SRAM)";
779 break;
780 case -1:
781 dang = "(RDB)";
782 break;
783 case 0:
784 dang = "[OS]";
785 if (dangerousdrive)
786 *dangerousdrive |= 1;
787 break;
788 }
789 if (nomedia) {
790 dang = "[NO MEDIA]";
791 if (dangerousdrive)
792 *dangerousdrive &= ~1;
793 }
794 if (uae_drives[index].readonly) {
795 rw = "RO";
796 if (dangerousdrive && !nomedia)
797 *dangerousdrive |= 2;
798 }
799
800 if (sectorsize)
801 *sectorsize = uae_drives[index].bytespersector;
802 if (flags & 1) {
803 if (nomedia) {
804 _tcscpy (tmp, "N/A");
805 } else {
806 if (size >= 1024 * 1024 * 1024)
807 _stprintf (tmp, "%.1fG", ((double)(uae_u32)(size / (1024 * 1024))) / 1024.0);
808 else if (size < 10 * 1024 * 1024)
809 _stprintf (tmp, "%dK", (int) (size / 1024));
810 else
811 _stprintf (tmp, "%.1fM", ((double)(uae_u32)(size / (1024))) / 1024.0);
812 }
813 _stprintf (name, "%10s [%s,%s] %s", dang, tmp, rw, uae_drives[index].device_name + 3);
814 return name;
815 }
816 if (flags & 2)
817 return uae_drives[index].device_path;
818 return uae_drives[index].device_name;
819 }
820