1 /////////////////////////////////////////////////////////////////////////
2 // $Id: hdimage.cc 14229 2021-04-18 17:20:41Z vruppert $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2002-2021 The Bochs Project
6 //
7 // This library is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU Lesser General Public
9 // License as published by the Free Software Foundation; either
10 // version 2 of the License, or (at your option) any later version.
11 //
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // Lesser General Public License for more details.
16 //
17 // You should have received a copy of the GNU Lesser General Public
18 // License along with this library; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 /////////////////////////////////////////////////////////////////////////
21
22 #ifdef BXIMAGE
23 #include "config.h"
24 #include "misc/bxcompat.h"
25 #include "osdep.h"
26 #include "misc/bswap.h"
27 #else
28 #include "bochs.h"
29 #include "gui/siminterface.h"
30 #include "param_names.h"
31 #include "plugin.h"
32 #include "cdrom.h"
33 #include "cdrom_amigaos.h"
34 #include "cdrom_misc.h"
35 #include "cdrom_osx.h"
36 #include "cdrom_win32.h"
37 #endif
38 #include "hdimage.h"
39
40 #if BX_HAVE_SYS_MMAN_H
41 #include <sys/mman.h>
42 #endif
43 #ifdef linux
44 #include <linux/fs.h>
45 #include <sys/ioctl.h>
46 #include <sys/wait.h>
47 #endif
48
49 #ifndef O_ACCMODE
50 #define O_ACCMODE (O_WRONLY | O_RDWR)
51 #endif
52
53 #define LOG_THIS bx_hdimage_ctl.
54
55 #ifndef BXIMAGE
56
57 bx_hdimage_ctl_c bx_hdimage_ctl;
58
59 const Bit8u n_hdimage_builtin_modes = 7;
60
61 const char *builtin_mode_names[n_hdimage_builtin_modes] = {
62 "flat",
63 "concat",
64 "sparse",
65 "dll",
66 "growing",
67 "undoable",
68 "volatile"
69 };
70
71 const char **hdimage_mode_names;
72
bx_hdimage_ctl_c()73 bx_hdimage_ctl_c::bx_hdimage_ctl_c()
74 {
75 put("hdimage", "IMG");
76 }
77
init(void)78 void bx_hdimage_ctl_c::init(void)
79 {
80 Bit8u count = n_hdimage_builtin_modes;
81
82 count += PLUG_get_plugins_count(PLUGTYPE_IMG);
83 hdimage_mode_names = (const char**) malloc((count + 1) * sizeof(char*));
84 for (Bit8u i = 0; i < n_hdimage_builtin_modes; i++) {
85 hdimage_mode_names[i] = builtin_mode_names[i];
86 }
87 Bit8u n = 0;
88 for (Bit8u i = n_hdimage_builtin_modes; i < count; i++) {
89 hdimage_mode_names[i] = PLUG_get_plugin_name(PLUGTYPE_IMG, n);
90 n++;
91 }
92 hdimage_mode_names[count] = NULL;
93 }
94
get_mode_names(void)95 const char **bx_hdimage_ctl_c::get_mode_names(void)
96 {
97 return hdimage_mode_names;
98 }
99
get_mode_id(const char * mode)100 int bx_hdimage_ctl_c::get_mode_id(const char *mode)
101 {
102 int i = 0;
103
104 while (hdimage_mode_names[i] != NULL) {
105 if (!strcmp(mode, hdimage_mode_names[i])) return i;
106 i++;
107 }
108 return -1;
109 }
110
list_modules(void)111 void bx_hdimage_ctl_c::list_modules(void)
112 {
113 char list[60];
114 Bit8u i = 0;
115 size_t len = 0, len1;
116
117 BX_INFO(("Disk image modules"));
118 list[0] = 0;
119 while (hdimage_mode_names[i] != NULL) {
120 len1 = strlen(hdimage_mode_names[i]);
121 if ((len + len1 + 1) > 58) {
122 BX_INFO((" %s", list));
123 list[0] = 0;
124 len = 0;
125 }
126 strcat(list, " ");
127 strcat(list, hdimage_mode_names[i]);
128 len = strlen(list);
129 i++;
130 }
131 if (len > 0) {
132 BX_INFO((" %s", list));
133 }
134 }
135
exit(void)136 void bx_hdimage_ctl_c::exit(void)
137 {
138 free(hdimage_mode_names);
139 hdimage_locator_c::cleanup();
140 }
141
init_image(const char * image_mode,Bit64u disk_size,const char * journal)142 device_image_t* bx_hdimage_ctl_c::init_image(const char *image_mode, Bit64u disk_size, const char *journal)
143 {
144 device_image_t *hdimage = NULL;
145
146 // instantiate the right class
147 if (!strcmp(image_mode, "flat")) {
148 hdimage = new flat_image_t();
149 } else if (!strcmp(image_mode, "concat")) {
150 hdimage = new concat_image_t();
151 #ifdef WIN32
152 } else if (!strcmp(image_mode, "dll")) {
153 hdimage = new dll_image_t();
154 #endif //DLL_HD_SUPPORT
155 } else if (!strcmp(image_mode, "sparse")) {
156 hdimage = new sparse_image_t();
157 } else if (!strcmp(image_mode, "undoable")) {
158 hdimage = new undoable_image_t(journal);
159 } else if (!strcmp(image_mode, "growing")) {
160 hdimage = new growing_image_t();
161 } else if (!strcmp(image_mode, "volatile")) {
162 hdimage = new volatile_image_t(journal);
163 } else {
164 if (!hdimage_locator_c::module_present(image_mode)) {
165 #if BX_PLUGINS
166 PLUG_load_plugin_var(image_mode, PLUGTYPE_IMG);
167 #else
168 BX_PANIC(("Disk image mode '%s' not available", image_mode));
169 #endif
170 }
171 hdimage = hdimage_locator_c::create(image_mode, disk_size, journal);
172 }
173 return hdimage;
174 }
175
init_cdrom(const char * dev)176 cdrom_base_c* bx_hdimage_ctl_c::init_cdrom(const char *dev)
177 {
178 #if BX_SUPPORT_CDROM
179 return new LOWLEVEL_CDROM(dev);
180 #else
181 return new cdrom_base_c(dev);
182 #endif
183 }
184
185 #endif // ifndef BXIMAGE
186
187 hdimage_locator_c *hdimage_locator_c::all = NULL;
188
189 //
190 // Each disk image module has a static locator class that registers
191 // here
192 //
hdimage_locator_c(const char * mode)193 hdimage_locator_c::hdimage_locator_c(const char *mode)
194 {
195 hdimage_locator_c *ptr;
196
197 this->mode = mode;
198 this->next = NULL;
199 if (all == NULL) {
200 all = this;
201 } else {
202 ptr = all;
203 while (ptr->next) ptr = ptr->next;
204 ptr->next = this;
205 }
206 }
207
~hdimage_locator_c()208 hdimage_locator_c::~hdimage_locator_c()
209 {
210 hdimage_locator_c *ptr = 0;
211
212 if (this == all) {
213 all = all->next;
214 } else {
215 ptr = all;
216 while (ptr != NULL) {
217 if (ptr->next != this) {
218 ptr = ptr->next;
219 } else {
220 break;
221 }
222 }
223 }
224 if (ptr) {
225 ptr->next = this->next;
226 }
227 }
228
module_present(const char * mode)229 bool hdimage_locator_c::module_present(const char *mode)
230 {
231 hdimage_locator_c *ptr;
232
233 for (ptr = all; ptr != NULL; ptr = ptr->next) {
234 if (strcmp(mode, ptr->mode) == 0)
235 return 1;
236 }
237 return 0;
238 }
239
cleanup()240 void hdimage_locator_c::cleanup()
241 {
242 #if BX_PLUGINS && !defined(BXIMAGE)
243 while (all != NULL) {
244 PLUG_unload_plugin_type(all->mode, PLUGTYPE_IMG);
245 }
246 #endif
247 }
248
249 //
250 // Called by common hdimage code to locate and create a device_image_t
251 // object
252 //
253 device_image_t*
create(const char * mode,Bit64u disk_size,const char * journal)254 hdimage_locator_c::create(const char *mode, Bit64u disk_size, const char *journal)
255 {
256 hdimage_locator_c *ptr = 0;
257
258 for (ptr = all; ptr != NULL; ptr = ptr->next) {
259 if (strcmp(mode, ptr->mode) == 0)
260 return (ptr->allocate(disk_size, journal));
261 }
262 return NULL;
263 }
264
detect_image_mode(int fd,Bit64u disk_size,const char ** image_mode)265 bool hdimage_locator_c::detect_image_mode(int fd, Bit64u disk_size,
266 const char **image_mode)
267 {
268 hdimage_locator_c *ptr = 0;
269
270 for (ptr = all; ptr != NULL; ptr = ptr->next) {
271 if (ptr->check_format(fd, disk_size) == HDIMAGE_FORMAT_OK) {
272 *image_mode = ptr->mode;
273 return 1;
274 }
275 }
276 return 0;
277 }
278
279 // helper functions
280
281 #ifdef BXIMAGE
bx_create_image_file(const char * filename)282 int bx_create_image_file(const char *filename)
283 {
284 int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC
285 #ifdef O_BINARY
286 | O_BINARY
287 #endif
288 , S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP
289 );
290 return fd;
291 }
292 #endif
293
bx_read_image(int fd,Bit64s offset,void * buf,int count)294 int bx_read_image(int fd, Bit64s offset, void *buf, int count)
295 {
296 if (lseek(fd, offset, SEEK_SET) == -1) {
297 return -1;
298 }
299 return read(fd, buf, count);
300 }
301
bx_write_image(int fd,Bit64s offset,void * buf,int count)302 int bx_write_image(int fd, Bit64s offset, void *buf, int count)
303 {
304 if (lseek(fd, offset, SEEK_SET) == -1) {
305 return -1;
306 }
307 return write(fd, buf, count);
308 }
309
bx_close_image(int fd,const char * pathname)310 int bx_close_image(int fd, const char *pathname)
311 {
312 #ifndef BXIMAGE
313 char lockfn[BX_PATHNAME_LEN];
314
315 sprintf(lockfn, "%s.lock", pathname);
316 if (access(lockfn, F_OK) == 0) {
317 unlink(lockfn);
318 }
319 #endif
320 return ::close(fd);
321 }
322
323 #ifndef WIN32
hdimage_open_file(const char * pathname,int flags,Bit64u * fsize,time_t * mtime)324 int hdimage_open_file(const char *pathname, int flags, Bit64u *fsize, time_t *mtime)
325 #else
326 int hdimage_open_file(const char *pathname, int flags, Bit64u *fsize, FILETIME *mtime)
327 #endif
328 {
329 #ifndef BXIMAGE
330 char lockfn[BX_PATHNAME_LEN];
331 int lockfd;
332 #endif
333
334 #ifdef WIN32
335 if (fsize != NULL) {
336 HANDLE hFile = CreateFile(pathname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL);
337 if (hFile != INVALID_HANDLE_VALUE) {
338 ULARGE_INTEGER FileSize;
339 FileSize.LowPart = GetFileSize(hFile, &FileSize.HighPart);
340 if (mtime != NULL) {
341 GetFileTime(hFile, NULL, NULL, mtime);
342 }
343 CloseHandle(hFile);
344 if ((FileSize.LowPart != INVALID_FILE_SIZE) || (GetLastError() == NO_ERROR)) {
345 *fsize = FileSize.QuadPart;
346 } else {
347 return -1;
348 }
349 } else {
350 return -1;
351 }
352 }
353 #endif
354
355 #ifndef BXIMAGE
356 sprintf(lockfn, "%s.lock", pathname);
357 lockfd = ::open(lockfn, O_RDONLY);
358 if (lockfd >= 0) {
359 ::close(lockfd);
360 if (SIM->get_param_bool(BXPN_UNLOCK_IMAGES)->get()) {
361 // Remove lock file if requested
362 if (access(lockfn, F_OK) == 0) {
363 unlink(lockfn);
364 }
365 } else {
366 // Opening image must fail if lock file exists.
367 BX_ERROR(("image locked: '%s'", pathname));
368 return -1;
369 }
370 }
371 #endif
372
373 int fd = ::open(pathname, flags
374 #ifdef O_BINARY
375 | O_BINARY
376 #endif
377 );
378
379 if (fd < 0) {
380 return fd;
381 }
382
383 #ifndef WIN32
384 if (fsize != NULL) {
385 struct stat stat_buf;
386 if (fstat(fd, &stat_buf)) {
387 BX_PANIC(("fstat() returns error!"));
388 return -1;
389 }
390 #ifdef linux
391 if (S_ISBLK(stat_buf.st_mode)) { // Is this a special device file (e.g. /dev/sde) ?
392 ioctl(fd, BLKGETSIZE64, fsize); // yes it's!
393 }
394 else
395 #endif
396 {
397 *fsize = (Bit64u)stat_buf.st_size; // standard unix procedure to get size of regular files
398 }
399 if (mtime != NULL) {
400 *mtime = stat_buf.st_mtime;
401 }
402 }
403 #endif
404 #ifndef BXIMAGE
405 if ((flags & O_ACCMODE) != O_RDONLY) {
406 lockfd = ::open(lockfn, O_CREAT | O_RDWR
407 #ifdef O_BINARY
408 | O_BINARY
409 #endif
410 , S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP);
411 if (lockfd >= 0) {
412 // lock this image
413 ::close(lockfd);
414 }
415 }
416 #endif
417 return fd;
418 }
419
hdimage_detect_image_mode(const char * pathname,const char ** image_mode)420 bool hdimage_detect_image_mode(const char *pathname, const char **image_mode)
421 {
422 bool result = false;
423 Bit64u image_size = 0;
424
425 #if BX_PLUGINS && !defined(BXIMAGE)
426 PLUG_load_plugin_var("*", PLUGTYPE_IMG);
427 #endif
428 int fd = hdimage_open_file(pathname, O_RDONLY, &image_size, NULL);
429 if (fd < 0) {
430 return result;
431 }
432
433 if (sparse_image_t::check_format(fd, image_size) == HDIMAGE_FORMAT_OK) {
434 *image_mode = "sparse";
435 result = true;
436 } else if (growing_image_t::check_format(fd, image_size) == HDIMAGE_FORMAT_OK) {
437 *image_mode = "growing";
438 result = true;
439 } else if (hdimage_locator_c::detect_image_mode(fd, image_size, image_mode)) {
440 result = true;
441 } else if (flat_image_t::check_format(fd, image_size) == HDIMAGE_FORMAT_OK) {
442 *image_mode = "flat";
443 result = true;
444 }
445 ::close(fd);
446
447 return result;
448 }
449
450 // if return_time==0, this returns the fat_date, else the fat_time
451 #ifndef WIN32
fat_datetime(time_t time,int return_time)452 Bit16u fat_datetime(time_t time, int return_time)
453 {
454 struct tm* t;
455 struct tm t1;
456
457 t = &t1;
458 localtime_r(&time, t);
459 if (return_time)
460 return htod16((t->tm_sec/2) | (t->tm_min<<5) | (t->tm_hour<<11));
461 return htod16((t->tm_mday) | ((t->tm_mon+1)<<5) | ((t->tm_year-80)<<9));
462 }
463 #else
fat_datetime(FILETIME time,int return_time)464 Bit16u fat_datetime(FILETIME time, int return_time)
465 {
466 SYSTEMTIME gmtsystime, systime;
467 TIME_ZONE_INFORMATION tzi;
468
469 FileTimeToSystemTime(&time, &gmtsystime);
470 GetTimeZoneInformation(&tzi);
471 SystemTimeToTzSpecificLocalTime(&tzi, &gmtsystime, &systime);
472 if (return_time)
473 return htod16((systime.wSecond/2) | (systime.wMinute<<5) | (systime.wHour<<11));
474 return htod16((systime.wDay) | (systime.wMonth<<5) | ((systime.wYear-1980)<<9));
475 }
476 #endif
477
478 #ifndef BXIMAGE
479 // generic save/restore functions
hdimage_save_handler(void * class_ptr,bx_param_c * param)480 Bit64s hdimage_save_handler(void *class_ptr, bx_param_c *param)
481 {
482 char imgname[BX_PATHNAME_LEN];
483 char path[BX_PATHNAME_LEN+1];
484
485 param->get_param_path(imgname, BX_PATHNAME_LEN);
486 if (!strncmp(imgname, "bochs.", 6)) {
487 strcpy(imgname, imgname+6);
488 }
489 if (SIM->get_param_string(BXPN_RESTORE_PATH)->isempty()) {
490 return 0;
491 }
492 sprintf(path, "%s/%s", SIM->get_param_string(BXPN_RESTORE_PATH)->getptr(), imgname);
493 return ((device_image_t*)class_ptr)->save_state(path);
494 }
495
hdimage_restore_handler(void * class_ptr,bx_param_c * param,Bit64s value)496 void hdimage_restore_handler(void *class_ptr, bx_param_c *param, Bit64s value)
497 {
498 char imgname[BX_PATHNAME_LEN];
499 char path[BX_PATHNAME_LEN+1];
500
501 if (value != 0) {
502 param->get_param_path(imgname, BX_PATHNAME_LEN);
503 if (!strncmp(imgname, "bochs.", 6)) {
504 strcpy(imgname, imgname+6);
505 }
506 sprintf(path, "%s/%s", SIM->get_param_string(BXPN_RESTORE_PATH)->getptr(), imgname);
507 ((device_image_t*)class_ptr)->restore_state(path);
508 }
509 }
510
hdimage_backup_file(int fd,const char * backup_fname)511 bool hdimage_backup_file(int fd, const char *backup_fname)
512 {
513 char *buf;
514 off_t offset;
515 int nread, size;
516 bool ret = 1;
517
518 int backup_fd = ::open(backup_fname, O_RDWR | O_CREAT | O_TRUNC
519 #ifdef O_BINARY
520 | O_BINARY
521 #endif
522 , S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP);
523 if (backup_fd >= 0) {
524 offset = 0;
525 size = 0x20000;
526 buf = new char[size];
527 if (buf == NULL) {
528 ::close(backup_fd);
529 return 0;
530 }
531 while ((nread = bx_read_image(fd, offset, buf, size)) > 0) {
532 if (bx_write_image(backup_fd, offset, buf, nread) < 0) {
533 ret = 0;
534 break;
535 }
536 if (nread < size) {
537 break;
538 }
539 offset += size;
540 };
541 if (nread < 0) {
542 ret = 0;
543 }
544 delete [] buf;
545 ::close(backup_fd);
546 return ret;
547 }
548 return 0;
549 }
550 #endif
551
hdimage_copy_file(const char * src,const char * dst)552 bool hdimage_copy_file(const char *src, const char *dst)
553 {
554 #ifdef WIN32
555 return (bool)CopyFile(src, dst, FALSE);
556 #elif defined(linux)
557 pid_t pid, ws;
558
559 if ((src == NULL) || (dst == NULL)) {
560 return 0;
561 }
562
563 if (!(pid = fork())) {
564 execl("/bin/cp", "/bin/cp", src, dst, (char *)0);
565 return 0;
566 }
567 wait(&ws);
568 if (!WIFEXITED(ws)) {
569 return -1;
570 }
571 return (WEXITSTATUS(ws) == 0);
572 #else
573 int fd1, fd2;
574 char *buf;
575 off_t offset;
576 int nread, size;
577 bool ret = 1;
578
579 fd1 = ::open(src, O_RDONLY
580 #ifdef O_BINARY
581 | O_BINARY
582 #endif
583 );
584 if (fd1 < 0) return 0;
585 fd2 = ::open(dst, O_RDWR | O_CREAT | O_TRUNC
586 #ifdef O_BINARY
587 | O_BINARY
588 #endif
589 , S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP);
590 if (fd2 < 0) {
591 ::close(fd1);
592 return 0;
593 }
594 offset = 0;
595 size = 0x20000;
596 buf = new char[size];
597 if (buf == NULL) {
598 ::close(fd1);
599 ::close(fd2);
600 return 0;
601 }
602 while ((nread = bx_read_image(fd1, offset, buf, size)) > 0) {
603 if (bx_write_image(fd2, offset, buf, nread) < 0) {
604 ret = 0;
605 break;
606 }
607 if (nread < size) {
608 break;
609 }
610 offset += size;
611 };
612 if (nread < 0) {
613 ret = 0;
614 }
615 delete [] buf;
616 ::close(fd1);
617 ::close(fd2);
618 return ret;
619 #endif
620 }
621
622 /*** base class device_image_t ***/
623
device_image_t()624 device_image_t::device_image_t()
625 {
626 cylinders = 0;
627 hd_size = 0;
628 sect_size = 512;
629 }
630
open(const char * _pathname)631 int device_image_t::open(const char* _pathname)
632 {
633 return open(_pathname, O_RDWR);
634 }
635
get_capabilities()636 Bit32u device_image_t::get_capabilities()
637 {
638 return (cylinders == 0) ? HDIMAGE_AUTO_GEOMETRY : 0;
639 }
640
get_timestamp()641 Bit32u device_image_t::get_timestamp()
642 {
643 return (fat_datetime(mtime, 1) | (fat_datetime(mtime, 0) << 16));
644 }
645
646 #ifndef BXIMAGE
register_state(bx_list_c * parent)647 void device_image_t::register_state(bx_list_c *parent)
648 {
649 bx_param_bool_c *image = new bx_param_bool_c(parent, "image", NULL, NULL, 0);
650 image->set_sr_handlers(this, hdimage_save_handler, hdimage_restore_handler);
651 }
652 #endif
653
654 /*** flat_image_t function definitions ***/
655
open(const char * _pathname,int flags)656 int flat_image_t::open(const char* _pathname, int flags)
657 {
658 pathname = _pathname;
659 if ((fd = hdimage_open_file(pathname, flags, &hd_size, &mtime)) < 0) {
660 return -1;
661 }
662 BX_INFO(("hd_size: " FMT_LL "u", hd_size));
663 if (hd_size <= 0) BX_PANIC(("size of disk image not detected / invalid"));
664 if ((hd_size % sect_size) != 0) {
665 BX_PANIC(("size of disk image must be multiple of %d bytes", sect_size));
666 }
667 return fd;
668 }
669
close()670 void flat_image_t::close()
671 {
672 if (fd > -1) {
673 bx_close_image(fd, pathname);
674 }
675 }
676
lseek(Bit64s offset,int whence)677 Bit64s flat_image_t::lseek(Bit64s offset, int whence)
678 {
679 return (Bit64s)::lseek(fd, (off_t)offset, whence);
680 }
681
read(void * buf,size_t count)682 ssize_t flat_image_t::read(void* buf, size_t count)
683 {
684 return ::read(fd, (char*) buf, count);
685 }
686
write(const void * buf,size_t count)687 ssize_t flat_image_t::write(const void* buf, size_t count)
688 {
689 return ::write(fd, (char*) buf, count);
690 }
691
check_format(int fd,Bit64u imgsize)692 int flat_image_t::check_format(int fd, Bit64u imgsize)
693 {
694 char buffer[512];
695
696 if ((imgsize <= 0) || ((imgsize % 512) != 0)) {
697 return HDIMAGE_SIZE_ERROR;
698 } else if (bx_read_image(fd, 0, buffer, 512) < 0) {
699 return HDIMAGE_READ_ERROR;
700 } else {
701 return HDIMAGE_FORMAT_OK;
702 }
703 }
704
705 #ifndef BXIMAGE
save_state(const char * backup_fname)706 bool flat_image_t::save_state(const char *backup_fname)
707 {
708 return hdimage_backup_file(fd, backup_fname);
709 }
710
restore_state(const char * backup_fname)711 void flat_image_t::restore_state(const char *backup_fname)
712 {
713 close();
714 if (!hdimage_copy_file(backup_fname, pathname)) {
715 BX_PANIC(("Failed to restore image '%s'", pathname));
716 return;
717 }
718 if (device_image_t::open(pathname) < 0) {
719 BX_PANIC(("Failed to open restored image '%s'", pathname));
720 }
721 }
722 #endif
723
724 // helper function for concat and sparse mode images
725
increment_string(char * str,int diff)726 char increment_string(char *str, int diff)
727 {
728 // find the last character of the string, and increment it.
729 char *p = str;
730 while (*p != 0) p++;
731 BX_ASSERT(p>str); // choke on zero length strings
732 p--; // point to last character of the string
733 (*p) += diff; // increment to next/previous ascii code.
734 BX_DEBUG(("increment string returning '%s'", str));
735 return (*p);
736 }
737
738 /*** concat_image_t function definitions ***/
739
concat_image_t()740 concat_image_t::concat_image_t()
741 {
742 curr_fd = -1;
743 }
744
increment_string(char * str)745 void concat_image_t::increment_string(char *str)
746 {
747 ::increment_string(str, +1);
748 }
749
open(const char * _pathname0,int flags)750 int concat_image_t::open(const char* _pathname0, int flags)
751 {
752 UNUSED(flags);
753 pathname0 = _pathname0;
754 char *pathname1 = new char[strlen(pathname0) + 1];
755 strcpy(pathname1, pathname0);
756 BX_DEBUG(("concat_image_t::open"));
757 Bit64s start_offset = 0;
758 for (int i=0; i<BX_CONCAT_MAX_IMAGES; i++) {
759 fd_table[i] = hdimage_open_file(pathname1, flags, &length_table[i], NULL);
760 if (fd_table[i] < 0) {
761 // open failed.
762 // if no FD was opened successfully, return -1 (fail).
763 if (i==0) return -1;
764 // otherwise, it only means that all images in the series have
765 // been opened. Record the number of fds opened successfully.
766 maxfd = i;
767 break;
768 }
769 BX_INFO(("concat_image: open image #%d: '%s', (" FMT_LL "u bytes)", i, pathname1, length_table[i]));
770 struct stat stat_buf;
771 int ret = fstat(fd_table[i], &stat_buf);
772 if (ret) {
773 BX_PANIC(("fstat() returns error!"));
774 }
775 #ifdef S_ISBLK
776 if (S_ISBLK(stat_buf.st_mode)) {
777 BX_PANIC(("block devices should REALLY NOT be used as concat images"));
778 }
779 #endif
780 if ((stat_buf.st_size % sect_size) != 0) {
781 BX_PANIC(("size of disk image must be multiple of %d bytes", sect_size));
782 }
783 start_offset_table[i] = start_offset;
784 start_offset += length_table[i];
785 increment_string(pathname1);
786 }
787 delete [] pathname1;
788 // start up with first image selected
789 total_offset = 0;
790 index = 0;
791 curr_fd = fd_table[0];
792 curr_min = 0;
793 curr_max = length_table[0]-1;
794 hd_size = start_offset;
795 BX_INFO(("hd_size: " FMT_LL "u", hd_size));
796 return 0; // success.
797 }
798
close()799 void concat_image_t::close()
800 {
801 BX_DEBUG(("concat_image_t.close"));
802 char *pathname1 = new char[strlen(pathname0) + 1];
803 strcpy(pathname1, pathname0);
804 for (int index = 0; index < maxfd; index++) {
805 if (fd_table[index] > -1) {
806 bx_close_image(fd_table[index], pathname1);
807 }
808 increment_string(pathname1);
809 }
810 delete [] pathname1;
811 }
812
lseek(Bit64s offset,int whence)813 Bit64s concat_image_t::lseek(Bit64s offset, int whence)
814 {
815 if ((offset % sect_size) != 0)
816 BX_PANIC(("lseek HD with offset not multiple of %d", sect_size));
817 BX_DEBUG(("concat_image_t.lseek(%d)", whence));
818 switch (whence) {
819 case SEEK_SET:
820 total_offset = offset;
821 break;
822 case SEEK_CUR:
823 total_offset += offset;
824 break;
825 case SEEK_END:
826 total_offset = hd_size - offset;
827 break;
828 default:
829 return -1;
830 }
831 // is this offset in this disk image?
832 if (total_offset < curr_min) {
833 // no, look at previous images
834 for (int i=index-1; i>=0; i--) {
835 if (total_offset >= start_offset_table[i]) {
836 index = i;
837 curr_fd = fd_table[i];
838 curr_min = start_offset_table[i];
839 curr_max = curr_min + length_table[i] - 1;
840 BX_DEBUG(("concat_image_t.lseek to earlier image, index=%d", index));
841 break;
842 }
843 }
844 } else if (total_offset > curr_max) {
845 // no, look at later images
846 for (int i=index+1; i<maxfd; i++) {
847 if (total_offset < (start_offset_table[i] + length_table[i])) {
848 index = i;
849 curr_fd = fd_table[i];
850 curr_min = start_offset_table[i];
851 curr_max = curr_min + length_table[i] - 1;
852 BX_DEBUG(("concat_image_t.lseek to earlier image, index=%d", index));
853 break;
854 }
855 }
856 }
857 // now offset should be within the current image.
858 offset = total_offset - start_offset_table[index];
859 if ((offset < 0) || (offset >= (Bit64s)length_table[index])) {
860 BX_PANIC(("concat_image_t.lseek to byte %ld failed", (long)offset));
861 return -1;
862 }
863 return (Bit64s)::lseek(curr_fd, (off_t)offset, SEEK_SET);
864 }
865
read(void * buf,size_t count)866 ssize_t concat_image_t::read(void* buf, size_t count)
867 {
868 size_t readmax, count1 = count;
869 ssize_t ret = -1;
870 char *buf1 = (char*)buf;
871
872 BX_DEBUG(("concat_image_t.read %ld bytes", (long)count));
873 do {
874 readmax = (size_t)(curr_max - total_offset + 1);
875 if (count1 > readmax) {
876 ret = ::read(curr_fd, buf1, readmax);
877 if (ret >= 0) {
878 buf1 += readmax;
879 count1 -= readmax;
880 ret = lseek(curr_max + 1, SEEK_SET);
881 }
882 } else {
883 ret = ::read(curr_fd, buf1, count1);
884 if (ret >= 0) {
885 ret = lseek(count1, SEEK_CUR);
886 }
887 break;
888 }
889 } while (ret > 0);
890 return (ret < 0) ? ret : count;
891 }
892
write(const void * buf,size_t count)893 ssize_t concat_image_t::write(const void* buf, size_t count)
894 {
895 size_t writemax, count1 = count;
896 ssize_t ret = -1;
897 char *buf1 = (char*)buf;
898
899 BX_DEBUG(("concat_image_t.write %ld bytes", (long)count));
900 do {
901 writemax = (size_t)(curr_max - total_offset + 1);
902 if (count1 > writemax) {
903 ret = ::write(curr_fd, buf1, writemax);
904 if (ret >= 0) {
905 buf1 += writemax;
906 count1 -= writemax;
907 ret = lseek(curr_max + 1, SEEK_SET);
908 }
909 } else {
910 ret = ::write(curr_fd, buf1, count1);
911 if (ret >= 0) {
912 ret = lseek(count1, SEEK_CUR);
913 }
914 break;
915 }
916 } while (ret > 0);
917 return (ret < 0) ? ret : count;
918 }
919
920 #ifndef BXIMAGE
save_state(const char * backup_fname)921 bool concat_image_t::save_state(const char *backup_fname)
922 {
923 bool ret = 1;
924 char tempfn[BX_PATHNAME_LEN];
925
926 for (int index = 0; index < maxfd; index++) {
927 sprintf(tempfn, "%s%d", backup_fname, index);
928 ret &= hdimage_backup_file(fd_table[index], tempfn);
929 if (ret == 0) break;
930 }
931 return ret;
932 }
933
restore_state(const char * backup_fname)934 void concat_image_t::restore_state(const char *backup_fname)
935 {
936 char tempfn[BX_PATHNAME_LEN];
937
938 close();
939 char *image_name = new char[strlen(pathname0) + 1];
940 strcpy(image_name, pathname0);
941 for (int index = 0; index < maxfd; index++) {
942 sprintf(tempfn, "%s%d", backup_fname, index);
943 if (!hdimage_copy_file(tempfn, image_name)) {
944 BX_PANIC(("Failed to restore concat image '%s'", image_name));
945 delete [] image_name;
946 return;
947 }
948 increment_string(image_name);
949 }
950 delete [] image_name;
951 device_image_t::open(pathname0);
952 }
953 #endif
954
955 /*** sparse_image_t function definitions ***/
956
sparse_image_t()957 sparse_image_t::sparse_image_t()
958 {
959 fd = -1;
960 pathname = NULL;
961 #ifdef _POSIX_MAPPED_FILES
962 mmap_header = NULL;
963 #endif
964 pagetable = NULL;
965 parent_image = NULL;
966 }
967
read_header()968 int sparse_image_t::read_header()
969 {
970 BX_ASSERT(sizeof(header) == SPARSE_HEADER_SIZE);
971
972 int ret = check_format(fd, underlying_filesize);
973 if (ret != HDIMAGE_FORMAT_OK) {
974 switch (ret) {
975 case HDIMAGE_READ_ERROR:
976 BX_PANIC(("sparse: could not read entire header"));
977 break;
978 case HDIMAGE_NO_SIGNATURE:
979 BX_PANIC(("sparse: failed header magic check"));
980 break;
981 case HDIMAGE_VERSION_ERROR:
982 BX_PANIC(("sparse: unknown version in header"));
983 break;
984 }
985 return -1;
986 }
987
988 ret = bx_read_image(fd, 0, &header, sizeof(header));
989 if (ret < 0) {
990 return -1;
991 }
992
993 pagesize = dtoh32(header.pagesize);
994 Bit32u numpages = dtoh32(header.numpages);
995
996 total_size = pagesize;
997 total_size *= numpages;
998
999 pagesize_shift = 0;
1000 while ((pagesize >> pagesize_shift) > 1) pagesize_shift++;
1001
1002 if ((Bit32u)(1 << pagesize_shift) != pagesize) {
1003 panic("failed block size header check");
1004 }
1005
1006 pagesize_mask = pagesize - 1;
1007
1008 size_t preamble_size = (sizeof(Bit32u) * numpages) + sizeof(header);
1009 data_start = 0;
1010 while ((size_t)data_start < preamble_size) data_start += pagesize;
1011
1012 bool did_mmap = 0;
1013
1014 #ifdef _POSIX_MAPPED_FILES
1015 // Try to memory map from the beginning of the file (0 is trivially a page multiple)
1016 void *mmap_header = mmap(NULL, preamble_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1017 if (mmap_header == MAP_FAILED) {
1018 BX_INFO(("failed to mmap sparse disk file - using conventional file access"));
1019 mmap_header = NULL;
1020 }
1021 else
1022 {
1023 mmap_length = preamble_size;
1024 did_mmap = 1;
1025 pagetable = ((Bit32u *) (((Bit8u *) mmap_header) + sizeof(header)));
1026 system_pagesize_mask = getpagesize() - 1;
1027 }
1028 #endif
1029
1030 if (!did_mmap) {
1031 pagetable = new Bit32u[numpages];
1032
1033 if (pagetable == NULL) {
1034 panic("could not allocate memory for sparse disk block table");
1035 }
1036
1037 ret = ::read(fd, pagetable, sizeof(Bit32u) * numpages);
1038
1039 if (ret < 0) {
1040 panic(strerror(errno));
1041 }
1042
1043 if ((int)(sizeof(Bit32u) * numpages) != ret) {
1044 panic("could not read entire block table");
1045 }
1046 }
1047 return 0;
1048 }
1049
open(const char * pathname0,int flags)1050 int sparse_image_t::open(const char* pathname0, int flags)
1051 {
1052 pathname = strdup(pathname0);
1053 BX_DEBUG(("sparse_image_t::open"));
1054
1055 if ((fd = hdimage_open_file(pathname, flags, &underlying_filesize, &mtime)) < 0) {
1056 return -1;
1057 }
1058 BX_DEBUG(("sparse_image: open image %s", pathname));
1059
1060 if (read_header() < 0) {
1061 return -1;
1062 }
1063
1064 if ((underlying_filesize % pagesize) != 0)
1065 panic("size of sparse disk image is not multiple of page size");
1066
1067 if ((pagesize % sect_size) != 0)
1068 panic("page size of sparse disk image is not multiple of sector size");
1069
1070 underlying_current_filepos = 0;
1071 if (-1 == ::lseek(fd, 0, SEEK_SET))
1072 panic("error while seeking to start of file");
1073
1074 lseek(0, SEEK_SET);
1075
1076 char * parentpathname = strdup(pathname);
1077 char lastchar = ::increment_string(parentpathname, -1);
1078
1079 if ((lastchar >= '0') && (lastchar <= '9'))
1080 {
1081 struct stat stat_buf;
1082 if (0 == stat(parentpathname, &stat_buf))
1083 {
1084 parent_image = new sparse_image_t();
1085 int ret = parent_image->open(parentpathname, flags);
1086 if (ret != 0) return ret;
1087 if ( (parent_image->pagesize != pagesize)
1088 || (parent_image->total_size != total_size))
1089 {
1090 panic("child drive image does not have same page count/page size configuration");
1091 }
1092 }
1093 }
1094
1095 if (parentpathname != NULL) free(parentpathname);
1096
1097 if (dtoh32(header.version) == SPARSE_HEADER_VERSION) {
1098 hd_size = dtoh64(header.disk);
1099 BX_INFO(("sparse: pagesize = 0x%x, data_start = 0x" FMT_LL "x", pagesize, data_start));
1100 }
1101
1102 return 0; // success
1103 }
1104
close()1105 void sparse_image_t::close()
1106 {
1107 BX_DEBUG(("concat_image_t.close"));
1108 #ifdef _POSIX_MAPPED_FILES
1109 if (mmap_header != NULL) {
1110 int ret = munmap(mmap_header, mmap_length);
1111 if (ret != 0)
1112 BX_INFO(("failed to un-memory map sparse disk file"));
1113 }
1114 pagetable = NULL; // We didn't malloc it
1115 #endif
1116 if (fd > -1) {
1117 bx_close_image(fd, pathname);
1118 }
1119 if (pathname != NULL) {
1120 free(pathname);
1121 }
1122 if (pagetable != NULL) {
1123 delete [] pagetable;
1124 }
1125 if (parent_image != NULL) {
1126 delete parent_image;
1127 }
1128 }
1129
lseek(Bit64s offset,int whence)1130 Bit64s sparse_image_t::lseek(Bit64s offset, int whence)
1131 {
1132 if ((offset % sect_size) != 0)
1133 BX_PANIC(("lseek HD with offset not multiple of %d", sect_size));
1134 if (whence != SEEK_SET)
1135 BX_PANIC(("lseek HD with whence not SEEK_SET"));
1136
1137 BX_DEBUG(("sparse_image_t::lseek(%d)", whence));
1138
1139 if (offset > total_size)
1140 {
1141 BX_PANIC(("sparse_image_t.lseek to byte %ld failed", (long)offset));
1142 return -1;
1143 }
1144
1145 set_virtual_page((Bit32u)(offset >> pagesize_shift));
1146 position_page_offset = (Bit32u)(offset & pagesize_mask);
1147
1148 return 0;
1149 }
1150
get_physical_offset()1151 inline Bit64s sparse_image_t::get_physical_offset()
1152 {
1153 Bit64s physical_offset = data_start;
1154 physical_offset += ((Bit64s)position_physical_page << pagesize_shift);
1155 physical_offset += position_page_offset;
1156 return physical_offset;
1157 }
1158
set_virtual_page(Bit32u new_virtual_page)1159 void sparse_image_t::set_virtual_page(Bit32u new_virtual_page)
1160 {
1161 position_virtual_page = new_virtual_page;
1162 position_physical_page = dtoh32(pagetable[position_virtual_page]);
1163 }
1164
read_page_fragment(Bit32u read_virtual_page,Bit32u read_page_offset,size_t read_size,void * buf)1165 ssize_t sparse_image_t::read_page_fragment(Bit32u read_virtual_page, Bit32u read_page_offset, size_t read_size, void * buf)
1166 {
1167 if (read_virtual_page != position_virtual_page)
1168 {
1169 set_virtual_page(read_virtual_page);
1170 }
1171
1172 position_page_offset = read_page_offset;
1173
1174 if (position_physical_page == SPARSE_PAGE_NOT_ALLOCATED)
1175 {
1176 if (parent_image != NULL)
1177 {
1178 return parent_image->read_page_fragment(read_virtual_page, read_page_offset, read_size, buf);
1179 }
1180 else
1181 {
1182 memset(buf, 0, read_size);
1183 }
1184 }
1185 else
1186 {
1187 Bit64s physical_offset = get_physical_offset();
1188
1189 if (physical_offset != underlying_current_filepos)
1190 {
1191 off_t ret = ::lseek(fd, (off_t)physical_offset, SEEK_SET);
1192 // underlying_current_filepos update deferred
1193 if (ret == -1)
1194 panic(strerror(errno));
1195 }
1196
1197 ssize_t readret = ::read(fd, buf, read_size);
1198
1199 if (readret == -1)
1200 {
1201 panic(strerror(errno));
1202 }
1203
1204 if ((size_t)readret != read_size)
1205 {
1206 panic("could not read block contents from file");
1207 }
1208
1209 underlying_current_filepos = physical_offset + read_size;
1210 }
1211
1212 return read_size;
1213 }
1214
read(void * buf,size_t count)1215 ssize_t sparse_image_t::read(void* buf, size_t count)
1216 {
1217 ssize_t total_read = 0;
1218
1219 BX_DEBUG(("sparse_image_t.read %ld bytes", (long)count));
1220
1221 while (count != 0)
1222 {
1223 size_t can_read = pagesize - position_page_offset;
1224 if (count < can_read) can_read = count;
1225
1226 BX_ASSERT (can_read != 0);
1227
1228 size_t was_read = (size_t)read_page_fragment(position_virtual_page, position_page_offset, can_read, buf);
1229
1230 if (was_read != can_read) {
1231 BX_PANIC(("could not read from sparse disk"));
1232 }
1233
1234 total_read += can_read;
1235
1236 position_page_offset += can_read;
1237 if (position_page_offset == pagesize)
1238 {
1239 position_page_offset = 0;
1240 set_virtual_page(position_virtual_page + 1);
1241 }
1242
1243 BX_ASSERT(position_page_offset < pagesize);
1244
1245 buf = (((Bit8u *) buf) + can_read);
1246 count -= can_read;
1247 }
1248
1249 return total_read;
1250 }
1251
panic(const char * message)1252 void sparse_image_t::panic(const char * message)
1253 {
1254 char buffer[1024];
1255 if (message == NULL)
1256 {
1257 snprintf(buffer, sizeof(buffer), "error with sparse disk image %s", pathname);
1258 }
1259 else
1260 {
1261 snprintf(buffer, sizeof(buffer), "error with sparse disk image %s - %s", pathname, message);
1262 }
1263 BX_PANIC(("%s", buffer));
1264 }
1265
write(const void * buf,size_t count)1266 ssize_t sparse_image_t::write(const void* buf, size_t count)
1267 {
1268 ssize_t total_written = 0;
1269
1270 Bit32u update_pagetable_start = position_virtual_page;
1271 Bit32u update_pagetable_count = 0;
1272
1273 BX_DEBUG(("sparse_image_t.write %ld bytes", (long)count));
1274
1275 while (count != 0)
1276 {
1277 size_t can_write = pagesize - position_page_offset;
1278 if (count < can_write) can_write = count;
1279
1280 BX_ASSERT (can_write != 0);
1281
1282 if (position_physical_page == SPARSE_PAGE_NOT_ALLOCATED)
1283 {
1284 // We just add on another page at the end of the file
1285 // Reclamation, compaction etc should currently be done off-line
1286
1287 Bit64s data_size = underlying_filesize - data_start;
1288 BX_ASSERT((data_size % pagesize) == 0);
1289
1290 Bit32u data_size_pages = (Bit32u)(data_size / pagesize);
1291 Bit32u next_data_page = data_size_pages;
1292
1293 pagetable[position_virtual_page] = htod32(next_data_page);
1294 position_physical_page = next_data_page;
1295
1296 Bit64s page_file_start = data_start + ((Bit64s)position_physical_page << pagesize_shift);
1297
1298 if (parent_image != NULL)
1299 {
1300 // If we have a parent, we must merge our portion with the parent
1301 void *writebuffer = NULL;
1302
1303 if (can_write == pagesize)
1304 {
1305 writebuffer = (void *) buf;
1306 }
1307 else
1308 {
1309 writebuffer = malloc(pagesize);
1310 if (writebuffer == NULL)
1311 panic("Cannot allocate sufficient memory for page-merge in write");
1312
1313 // Read entire page - could optimize, but simple for now
1314 parent_image->read_page_fragment(position_virtual_page, 0, pagesize, writebuffer);
1315
1316 void *dest_start = ((Bit8u *) writebuffer) + position_page_offset;
1317 memcpy(dest_start, buf, can_write);
1318 }
1319
1320 int ret = (int)::lseek(fd, page_file_start, SEEK_SET);
1321 // underlying_current_filepos update deferred
1322 if (ret == -1) panic(strerror(errno));
1323
1324 ret = ::write(fd, writebuffer, pagesize);
1325 if (ret == -1) panic(strerror(errno));
1326
1327 if (pagesize != (Bit32u)ret) panic("failed to write entire merged page to disk");
1328
1329 if (can_write != pagesize)
1330 {
1331 free(writebuffer);
1332 }
1333 }
1334 else
1335 {
1336 // We need to write a zero page because read has been returning zeroes
1337 // We seek as close to the page end as possible, and then write a little
1338 // This produces a sparse file which has blanks
1339 // Also very quick, even when pagesize is massive
1340 int ret = (int)::lseek(fd, page_file_start + pagesize - 4, SEEK_SET);
1341 // underlying_current_filepos update deferred
1342 if (ret == -1) panic(strerror(errno));
1343
1344 Bit32u zero = 0;
1345 ret = ::write(fd, &zero, 4);
1346 if (ret == -1) panic(strerror(errno));
1347
1348 if (ret != 4) panic("failed to write entire blank page to disk");
1349 }
1350
1351 update_pagetable_count = (position_virtual_page - update_pagetable_start) + 1;
1352 underlying_filesize = underlying_current_filepos = page_file_start + pagesize;
1353 }
1354
1355 BX_ASSERT(position_physical_page != SPARSE_PAGE_NOT_ALLOCATED);
1356
1357 Bit64s physical_offset = get_physical_offset();
1358
1359 if (physical_offset != underlying_current_filepos)
1360 {
1361 off_t ret = ::lseek(fd, (off_t)physical_offset, SEEK_SET);
1362 // underlying_current_filepos update deferred
1363 if (ret == -1)
1364 panic(strerror(errno));
1365 }
1366
1367 ssize_t writeret = ::write(fd, buf, can_write);
1368
1369 if (writeret == -1)
1370 {
1371 panic(strerror(errno));
1372 }
1373
1374 if ((size_t)writeret != can_write)
1375 {
1376 panic("could not write block contents to file");
1377 }
1378
1379 underlying_current_filepos = physical_offset + can_write;
1380
1381 total_written += can_write;
1382
1383 position_page_offset += can_write;
1384 if (position_page_offset == pagesize)
1385 {
1386 position_page_offset = 0;
1387 set_virtual_page(position_virtual_page + 1);
1388 }
1389
1390 BX_ASSERT(position_page_offset < pagesize);
1391
1392 buf = (((Bit8u *) buf) + can_write);
1393 count -= can_write;
1394 }
1395
1396 if (update_pagetable_count != 0)
1397 {
1398 bool done = 0;
1399 off_t pagetable_write_from = sizeof(header) + (sizeof(Bit32u) * update_pagetable_start);
1400 size_t write_bytecount = update_pagetable_count * sizeof(Bit32u);
1401
1402 #ifdef _POSIX_MAPPED_FILES
1403 if (mmap_header != NULL)
1404 {
1405 // Sync from the beginning of the page
1406 size_t system_page_offset = pagetable_write_from & system_pagesize_mask;
1407 void *start = ((Bit8u *) mmap_header + pagetable_write_from - system_page_offset);
1408
1409 int ret = msync(start, system_page_offset + write_bytecount, MS_ASYNC);
1410
1411 if (ret != 0)
1412 panic(strerror(errno));
1413
1414 done = 1;
1415 }
1416 #endif
1417
1418 if (!done)
1419 {
1420 int ret = (int)::lseek(fd, pagetable_write_from, SEEK_SET);
1421 // underlying_current_filepos update deferred
1422 if (ret == -1) panic(strerror(errno));
1423
1424 ret = ::write(fd, &pagetable[update_pagetable_start], write_bytecount);
1425 if (ret == -1) panic(strerror(errno));
1426 if ((size_t)ret != write_bytecount) panic("could not write entire updated block header");
1427
1428 underlying_current_filepos = pagetable_write_from + write_bytecount;
1429 }
1430 }
1431
1432 return total_written;
1433 }
1434
check_format(int fd,Bit64u imgsize)1435 int sparse_image_t::check_format(int fd, Bit64u imgsize)
1436 {
1437 sparse_header_t temp_header;
1438
1439 int ret = ::read(fd, &temp_header, sizeof(temp_header));
1440 if (ret < 0) {
1441 return HDIMAGE_READ_ERROR;
1442 }
1443 if (ret != sizeof(temp_header)) {
1444 return HDIMAGE_READ_ERROR;
1445 }
1446
1447 if (dtoh32(temp_header.magic) != SPARSE_HEADER_MAGIC) {
1448 return HDIMAGE_NO_SIGNATURE;
1449 }
1450
1451 if ((dtoh32(temp_header.version) != SPARSE_HEADER_VERSION) &&
1452 (dtoh32(temp_header.version) != SPARSE_HEADER_V1)) {
1453 return HDIMAGE_VERSION_ERROR;
1454 }
1455
1456 return HDIMAGE_FORMAT_OK;
1457 }
1458
1459 #ifdef BXIMAGE
create_image(const char * pathname,Bit64u size)1460 int sparse_image_t::create_image(const char *pathname, Bit64u size)
1461 {
1462 Bit64u numpages;
1463 sparse_header_t header;
1464 size_t sizesofar;
1465 int padtopagesize;
1466
1467 memset(&header, 0, sizeof(header));
1468 header.magic = htod32(SPARSE_HEADER_MAGIC);
1469 header.version = htod32(SPARSE_HEADER_VERSION);
1470
1471 header.pagesize = htod32((1 << 10) * 32); // Use 32 KB Pages - could be configurable
1472 numpages = (size / dtoh32(header.pagesize)) + 1;
1473
1474 header.numpages = htod32((Bit32u)numpages);
1475 header.disk = htod64(size);
1476
1477 if (numpages != dtoh32(header.numpages)) {
1478 BX_FATAL(("ERROR: The disk image is too large for a sparse image!"));
1479 // Could increase page size here.
1480 // But note this only happens at 128 Terabytes!
1481 }
1482
1483 int fd = bx_create_image_file(pathname);
1484 if (fd < 0)
1485 BX_FATAL(("ERROR: failed to create sparse image file"));
1486 if (bx_write_image(fd, 0, &header, sizeof(header)) != sizeof(header)) {
1487 ::close(fd);
1488 BX_FATAL(("ERROR: The disk image is not complete - could not write header!"));
1489 }
1490
1491 Bit32u *pagetable = new Bit32u[dtoh32(header.numpages)];
1492 if (pagetable == NULL)
1493 BX_FATAL(("ERROR: The disk image is not complete - could not create pagetable!"));
1494 for (Bit32u i=0; i<dtoh32(header.numpages); i++)
1495 pagetable[i] = htod32(SPARSE_PAGE_NOT_ALLOCATED);
1496
1497 if (bx_write_image(fd, sizeof(header), pagetable, 4 * dtoh32(header.numpages)) != (int)(4 * dtoh32(header.numpages))) {
1498 ::close(fd);
1499 BX_FATAL(("ERROR: The disk image is not complete - could not write pagetable!"));
1500 }
1501 delete [] pagetable;
1502
1503 sizesofar = SPARSE_HEADER_SIZE + (4 * dtoh32(header.numpages));
1504 padtopagesize = dtoh32(header.pagesize) - (sizesofar & (dtoh32(header.pagesize) - 1));
1505
1506 Bit8u *padding = new Bit8u[padtopagesize];
1507 memset(padding, 0, padtopagesize);
1508
1509 if (bx_write_image(fd, sizesofar, padding, padtopagesize) != padtopagesize) {
1510 ::close(fd);
1511 BX_FATAL(("ERROR: The disk image is not complete - could not write padding!"));
1512 }
1513 delete [] padding;
1514 ::close(fd);
1515 return 0;
1516 }
1517 #else
save_state(const char * backup_fname)1518 bool sparse_image_t::save_state(const char *backup_fname)
1519 {
1520 return hdimage_backup_file(fd, backup_fname);
1521 }
1522
restore_state(const char * backup_fname)1523 void sparse_image_t::restore_state(const char *backup_fname)
1524 {
1525 int backup_fd;
1526 Bit64u imgsize = 0;
1527 char *temp_pathname;
1528
1529 if ((backup_fd = hdimage_open_file(backup_fname, O_RDONLY, &imgsize, NULL)) < 0) {
1530 BX_PANIC(("Could not open sparse image backup"));
1531 return;
1532 }
1533 if (check_format(backup_fd, imgsize) != HDIMAGE_FORMAT_OK) {
1534 ::close(backup_fd);
1535 BX_PANIC(("Could not detect sparse image header"));
1536 return;
1537 }
1538 ::close(backup_fd);
1539 temp_pathname = strdup(pathname);
1540 close();
1541 if (!hdimage_copy_file(backup_fname, temp_pathname)) {
1542 BX_PANIC(("Failed to restore sparse image '%s'", temp_pathname));
1543 free(temp_pathname);
1544 return;
1545 }
1546 if (device_image_t::open(temp_pathname) < 0) {
1547 BX_PANIC(("Failed to open restored image '%s'", temp_pathname));
1548 }
1549 free(temp_pathname);
1550 }
1551 #endif
1552
1553 #ifdef WIN32
1554
1555 /*** dll_image_t function definitions ***/
1556
1557 typedef int (CDECL *vdisk_open_t) (const char *path, int flags);
1558 typedef BOOL (CDECL *vdisk_read_t) (int vunit, LONGLONG blk, void *buf);
1559 typedef BOOL (CDECL *vdisk_write_t) (int vunit, LONGLONG blk, const void *buf);
1560 typedef void (CDECL *vdisk_close_t) (int vunit);
1561 typedef LONGLONG (CDECL *vdisk_get_size_t) (int vunit);
1562
1563 HINSTANCE hlib_vdisk = NULL;
1564 vdisk_open_t vdisk_open = NULL;
1565 vdisk_read_t vdisk_read = NULL;
1566 vdisk_write_t vdisk_write = NULL;
1567 vdisk_close_t vdisk_close = NULL;
1568 vdisk_get_size_t vdisk_get_size = NULL;
1569
dll_image_t()1570 dll_image_t::dll_image_t()
1571 {
1572 if (hlib_vdisk == NULL) {
1573 hlib_vdisk = LoadLibrary("vdisk.dll");
1574 if (hlib_vdisk != NULL) {
1575 vdisk_open = (vdisk_open_t) GetProcAddress(hlib_vdisk,"vdisk_open");
1576 vdisk_read = (vdisk_read_t) GetProcAddress(hlib_vdisk,"vdisk_read");
1577 vdisk_write = (vdisk_write_t) GetProcAddress(hlib_vdisk,"vdisk_write");
1578 vdisk_close = (vdisk_close_t) GetProcAddress(hlib_vdisk,"vdisk_close");
1579 vdisk_get_size = (vdisk_get_size_t) GetProcAddress(hlib_vdisk,"vdisk_get_size");
1580 if ((vdisk_open == NULL) || (vdisk_read == NULL) || (vdisk_write == NULL) ||
1581 (vdisk_close == NULL) || (vdisk_get_size == NULL)) {
1582 FreeLibrary(hlib_vdisk);
1583 hlib_vdisk = NULL;
1584 }
1585 }
1586 }
1587 }
1588
open(const char * pathname,int flags)1589 int dll_image_t::open(const char* pathname, int flags)
1590 {
1591 if (hlib_vdisk != NULL) {
1592 vunit = vdisk_open(pathname, flags);
1593 if (vunit >= 0) {
1594 hd_size = (Bit64u)vdisk_get_size(vunit) << 9;
1595 sect_size = 512;
1596 vblk = 0;
1597 }
1598 } else {
1599 vunit = -2;
1600 }
1601 return vunit;
1602 }
1603
close()1604 void dll_image_t::close()
1605 {
1606 if ((vunit >= 0) && (hlib_vdisk != NULL)) {
1607 vdisk_close(vunit);
1608 }
1609 }
1610
lseek(Bit64s offset,int whence)1611 Bit64s dll_image_t::lseek(Bit64s offset, int whence)
1612 {
1613 if (whence == SEEK_SET) {
1614 vblk = offset >> 9;
1615 } else if (whence == SEEK_CUR) {
1616 vblk += offset >> 9;
1617 } else {
1618 BX_ERROR(("lseek: mode not supported yet"));
1619 return -1;
1620 }
1621 if (vblk >= (Bit64s)(hd_size >> 9))
1622 return -1;
1623 return 0;
1624 }
1625
read(void * buf,size_t count)1626 ssize_t dll_image_t::read(void* buf, size_t count)
1627 {
1628 if ((vunit >= 0) && (hlib_vdisk != NULL)) {
1629 if (vdisk_read(vunit, vblk, buf)) {
1630 vblk++;
1631 return count;
1632 }
1633 }
1634 return -1;
1635 }
1636
write(const void * buf,size_t count)1637 ssize_t dll_image_t::write(const void* buf, size_t count)
1638 {
1639 if ((vunit >= 0) && (hlib_vdisk != 0)) {
1640 if (vdisk_write(vunit, vblk, buf)) {
1641 vblk++;
1642 return count;
1643 }
1644 }
1645 return -1;
1646 }
1647 #endif // DLL_HD_SUPPORT
1648
1649 // redolog implementation
redolog_t()1650 redolog_t::redolog_t()
1651 {
1652 fd = -1;
1653 pathname = NULL;
1654 catalog = NULL;
1655 bitmap = NULL;
1656 extent_index = (Bit32u)0;
1657 extent_offset = (Bit32u)0;
1658 extent_next = (Bit32u)0;
1659 }
1660
print_header()1661 void redolog_t::print_header()
1662 {
1663 BX_INFO(("redolog : Standard Header : magic='%s', type='%s', subtype='%s', version = %d.%d",
1664 header.standard.magic, header.standard.type, header.standard.subtype,
1665 dtoh32(header.standard.version)/0x10000,
1666 dtoh32(header.standard.version)%0x10000));
1667 if (dtoh32(header.standard.version) == STANDARD_HEADER_VERSION) {
1668 BX_INFO(("redolog : Specific Header : #entries=%d, bitmap size=%d, exent size = %d disk size = " FMT_LL "d",
1669 dtoh32(header.specific.catalog),
1670 dtoh32(header.specific.bitmap),
1671 dtoh32(header.specific.extent),
1672 dtoh64(header.specific.disk)));
1673 } else if (dtoh32(header.standard.version) == STANDARD_HEADER_V1) {
1674 redolog_header_v1_t header_v1;
1675 memcpy(&header_v1, &header, STANDARD_HEADER_SIZE);
1676 BX_INFO(("redolog : Specific Header : #entries=%d, bitmap size=%d, exent size = %d disk size = " FMT_LL "d",
1677 dtoh32(header_v1.specific.catalog),
1678 dtoh32(header_v1.specific.bitmap),
1679 dtoh32(header_v1.specific.extent),
1680 dtoh64(header_v1.specific.disk)));
1681 }
1682 }
1683
make_header(const char * type,Bit64u size)1684 int redolog_t::make_header(const char* type, Bit64u size)
1685 {
1686 Bit32u entries, extent_size, bitmap_size;
1687 Bit64u maxsize;
1688 Bit32u flip=0;
1689
1690 // Set standard header values
1691 memset(&header, 0, sizeof(redolog_header_t));
1692 strcpy((char*)header.standard.magic, STANDARD_HEADER_MAGIC);
1693 strcpy((char*)header.standard.type, REDOLOG_TYPE);
1694 strcpy((char*)header.standard.subtype, type);
1695 header.standard.version = htod32(STANDARD_HEADER_VERSION);
1696 header.standard.header = htod32(STANDARD_HEADER_SIZE);
1697
1698 entries = 512;
1699 bitmap_size = 1;
1700
1701 // Compute #entries and extent size values
1702 do {
1703 extent_size = 8 * bitmap_size * 512;
1704
1705 header.specific.catalog = htod32(entries);
1706 header.specific.bitmap = htod32(bitmap_size);
1707 header.specific.extent = htod32(extent_size);
1708
1709 maxsize = (Bit64u)entries * (Bit64u)extent_size;
1710
1711 flip++;
1712
1713 if(flip&0x01) bitmap_size *= 2;
1714 else entries *= 2;
1715 } while (maxsize < size);
1716
1717 header.specific.timestamp = 0;
1718 header.specific.disk = htod64(size);
1719
1720 print_header();
1721
1722 catalog = new Bit32u[dtoh32(header.specific.catalog)];
1723 bitmap = new Bit8u[dtoh32(header.specific.bitmap)];
1724
1725 if ((catalog == NULL) || (bitmap==NULL))
1726 BX_PANIC(("redolog : could not malloc catalog or bitmap"));
1727
1728 for (Bit32u i=0; i<dtoh32(header.specific.catalog); i++)
1729 catalog[i] = htod32(REDOLOG_PAGE_NOT_ALLOCATED);
1730
1731 bitmap_blocks = 1 + (dtoh32(header.specific.bitmap) - 1) / 512;
1732 extent_blocks = 1 + (dtoh32(header.specific.extent) - 1) / 512;
1733
1734 BX_DEBUG(("redolog : each bitmap is %d blocks", bitmap_blocks));
1735 BX_DEBUG(("redolog : each extent is %d blocks", extent_blocks));
1736
1737 return 0;
1738 }
1739
create(const char * filename,const char * type,Bit64u size)1740 int redolog_t::create(const char* filename, const char* type, Bit64u size)
1741 {
1742 #ifndef BXIMAGE
1743 char lockfn[BX_PATHNAME_LEN];
1744
1745 sprintf(lockfn, "%s.lock", filename);
1746 if (access(lockfn, F_OK) == 0) {
1747 return -1;
1748 }
1749 #endif
1750
1751 BX_INFO(("redolog : creating redolog %s", filename));
1752
1753 int filedes = ::open(filename, O_RDWR | O_CREAT | O_TRUNC
1754 #ifdef O_BINARY
1755 | O_BINARY
1756 #endif
1757 , S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP);
1758
1759 return create(filedes, type, size);
1760 }
1761
create(int filedes,const char * type,Bit64u size)1762 int redolog_t::create(int filedes, const char* type, Bit64u size)
1763 {
1764 fd = filedes;
1765
1766 if (fd < 0)
1767 {
1768 return -1; // open failed
1769 }
1770
1771 if (make_header(type, size) < 0)
1772 {
1773 return -1;
1774 }
1775
1776 // Write header
1777 ::write(fd, &header, dtoh32(header.standard.header));
1778
1779 // Write catalog
1780 // FIXME could mmap
1781 ::write(fd, catalog, dtoh32(header.specific.catalog) * sizeof (Bit32u));
1782
1783 return 0;
1784 }
1785
open(const char * filename,const char * type)1786 int redolog_t::open(const char* filename, const char *type)
1787 {
1788 return open(filename, type, O_RDWR);
1789 }
1790
open(const char * filename,const char * type,int flags)1791 int redolog_t::open(const char* filename, const char *type, int flags)
1792 {
1793 Bit64u imgsize = 0;
1794 #ifndef WIN32
1795 time_t mtime;
1796 #else
1797 FILETIME mtime;
1798 #endif
1799
1800 pathname = new char[strlen(filename) + 1];
1801 strcpy(pathname, filename);
1802 fd = hdimage_open_file(filename, flags, &imgsize, &mtime);
1803 if (fd < 0) {
1804 BX_INFO(("redolog : could not open image %s", filename));
1805 // open failed.
1806 return -1;
1807 }
1808 BX_INFO(("redolog : open image %s", filename));
1809
1810 int res = check_format(fd, type);
1811 if (res != HDIMAGE_FORMAT_OK) {
1812 switch (res) {
1813 case HDIMAGE_READ_ERROR:
1814 BX_PANIC(("redolog : could not read header"));
1815 break;
1816 case HDIMAGE_NO_SIGNATURE:
1817 BX_PANIC(("redolog : Bad header magic"));
1818 break;
1819 case HDIMAGE_TYPE_ERROR:
1820 BX_PANIC(("redolog : Bad header type or subtype"));
1821 break;
1822 case HDIMAGE_VERSION_ERROR:
1823 BX_PANIC(("redolog : Bad header version"));
1824 break;
1825 }
1826 return -1;
1827 }
1828
1829 if (bx_read_image(fd, 0, &header, sizeof(header)) < 0) {
1830 return -1;
1831 }
1832 print_header();
1833
1834 if (dtoh32(header.standard.version) == STANDARD_HEADER_V1) {
1835 redolog_header_v1_t header_v1;
1836
1837 memcpy(&header_v1, &header, STANDARD_HEADER_SIZE);
1838 header.specific.disk = header_v1.specific.disk;
1839 }
1840 if (!strcmp(type, REDOLOG_SUBTYPE_GROWING)) {
1841 set_timestamp(fat_datetime(mtime, 1) | (fat_datetime(mtime, 0) << 16));
1842 }
1843
1844 catalog = new Bit32u[dtoh32(header.specific.catalog)];
1845
1846 // FIXME could mmap
1847 res = bx_read_image(fd, dtoh32(header.standard.header), catalog, dtoh32(header.specific.catalog) * sizeof(Bit32u));
1848
1849 if (res != (ssize_t)(dtoh32(header.specific.catalog) * sizeof(Bit32u)))
1850 {
1851 BX_PANIC(("redolog : could not read catalog %d=%d",res, dtoh32(header.specific.catalog)));
1852 return -1;
1853 }
1854
1855 // check last used extent
1856 extent_next = 0;
1857 for (Bit32u i=0; i < dtoh32(header.specific.catalog); i++)
1858 {
1859 if (dtoh32(catalog[i]) != REDOLOG_PAGE_NOT_ALLOCATED)
1860 {
1861 if (dtoh32(catalog[i]) >= extent_next)
1862 extent_next = dtoh32(catalog[i]) + 1;
1863 }
1864 }
1865 BX_INFO(("redolog : next extent will be at index %d",extent_next));
1866
1867 // memory used for storing bitmaps
1868 bitmap = new Bit8u[dtoh32(header.specific.bitmap)];
1869
1870 bitmap_blocks = 1 + (dtoh32(header.specific.bitmap) - 1) / 512;
1871 extent_blocks = 1 + (dtoh32(header.specific.extent) - 1) / 512;
1872
1873 BX_DEBUG(("redolog : each bitmap is %d blocks", bitmap_blocks));
1874 BX_DEBUG(("redolog : each extent is %d blocks", extent_blocks));
1875
1876 imagepos = 0;
1877 bitmap_update = 1;
1878
1879 return 0;
1880 }
1881
close()1882 void redolog_t::close()
1883 {
1884 if (fd >= 0)
1885 bx_close_image(fd, pathname);
1886
1887 if (pathname != NULL)
1888 delete [] pathname;
1889
1890 if (catalog != NULL)
1891 delete [] catalog;
1892
1893 if (bitmap != NULL)
1894 delete [] bitmap;
1895 }
1896
get_size()1897 Bit64u redolog_t::get_size()
1898 {
1899 return dtoh64(header.specific.disk);
1900 }
1901
get_timestamp()1902 Bit32u redolog_t::get_timestamp()
1903 {
1904 return dtoh32(header.specific.timestamp);
1905 }
1906
set_timestamp(Bit32u timestamp)1907 bool redolog_t::set_timestamp(Bit32u timestamp)
1908 {
1909 header.specific.timestamp = htod32(timestamp);
1910 // Update header
1911 bx_write_image(fd, 0, &header, dtoh32(header.standard.header));
1912 return 1;
1913 }
1914
lseek(Bit64s offset,int whence)1915 Bit64s redolog_t::lseek(Bit64s offset, int whence)
1916 {
1917 if ((offset % 512) != 0) {
1918 BX_PANIC(("redolog : lseek() offset not multiple of 512"));
1919 return -1;
1920 }
1921 if (whence == SEEK_SET) {
1922 imagepos = offset;
1923 } else if (whence == SEEK_CUR) {
1924 imagepos += offset;
1925 } else {
1926 BX_PANIC(("redolog: lseek() mode not supported yet"));
1927 return -1;
1928 }
1929 if (imagepos > (Bit64s)dtoh64(header.specific.disk)) {
1930 BX_PANIC(("redolog : lseek() to byte %ld failed", (long)offset));
1931 return -1;
1932 }
1933
1934 Bit32u old_extent_index = extent_index;
1935 extent_index = (Bit32u)(imagepos / dtoh32(header.specific.extent));
1936 if (extent_index != old_extent_index) {
1937 bitmap_update = 1;
1938 }
1939 extent_offset = (Bit32u)((imagepos % dtoh32(header.specific.extent)) / 512);
1940
1941 BX_DEBUG(("redolog : lseeking extent index %d, offset %d",extent_index, extent_offset));
1942
1943 return imagepos;
1944 }
1945
read(void * buf,size_t count)1946 ssize_t redolog_t::read(void* buf, size_t count)
1947 {
1948 Bit64s block_offset, bitmap_offset;
1949 ssize_t ret;
1950
1951 if (count != 512) {
1952 BX_PANIC(("redolog : read() with count not 512"));
1953 return -1;
1954 }
1955
1956 BX_DEBUG(("redolog : reading index %d, mapping to %d", extent_index, dtoh32(catalog[extent_index])));
1957
1958 if (dtoh32(catalog[extent_index]) == REDOLOG_PAGE_NOT_ALLOCATED) {
1959 // page not allocated
1960 return 0;
1961 }
1962
1963 bitmap_offset = (Bit64s)STANDARD_HEADER_SIZE + (dtoh32(header.specific.catalog) * sizeof(Bit32u));
1964 bitmap_offset += (Bit64s)512 * dtoh32(catalog[extent_index]) * (extent_blocks + bitmap_blocks);
1965 block_offset = bitmap_offset + ((Bit64s)512 * (bitmap_blocks + extent_offset));
1966
1967 BX_DEBUG(("redolog : bitmap offset is %x", (Bit32u)bitmap_offset));
1968 BX_DEBUG(("redolog : block offset is %x", (Bit32u)block_offset));
1969
1970 if (bitmap_update) {
1971 if (bx_read_image(fd, (off_t)bitmap_offset, bitmap, dtoh32(header.specific.bitmap)) != (ssize_t)dtoh32(header.specific.bitmap)) {
1972 BX_PANIC(("redolog : failed to read bitmap for extent %d", extent_index));
1973 return -1;
1974 }
1975 bitmap_update = 0;
1976 }
1977
1978 if (((bitmap[extent_offset/8] >> (extent_offset%8)) & 0x01) == 0x00) {
1979 BX_DEBUG(("read not in redolog"));
1980
1981 // bitmap says block not in redolog
1982 return 0;
1983 }
1984
1985 ret = bx_read_image(fd, (off_t)block_offset, buf, count);
1986 if (ret >= 0) lseek(512, SEEK_CUR);
1987
1988 return ret;
1989 }
1990
write(const void * buf,size_t count)1991 ssize_t redolog_t::write(const void* buf, size_t count)
1992 {
1993 Bit32u i;
1994 Bit64s block_offset, bitmap_offset, catalog_offset;
1995 ssize_t written;
1996 bool update_catalog = 0;
1997
1998 if (count != 512) {
1999 BX_PANIC(("redolog : write() with count not 512"));
2000 return -1;
2001 }
2002
2003 BX_DEBUG(("redolog : writing index %d, mapping to %d", extent_index, dtoh32(catalog[extent_index])));
2004
2005 if (dtoh32(catalog[extent_index]) == REDOLOG_PAGE_NOT_ALLOCATED) {
2006 if (extent_next >= dtoh32(header.specific.catalog)) {
2007 BX_PANIC(("redolog : can't allocate new extent... catalog is full"));
2008 return -1;
2009 }
2010
2011 BX_DEBUG(("redolog : allocating new extent at %d", extent_next));
2012
2013 // Extent not allocated, allocate new
2014 catalog[extent_index] = htod32(extent_next);
2015
2016 extent_next += 1;
2017
2018 char *zerobuffer = new char[512];
2019 memset(zerobuffer, 0, 512);
2020
2021 // Write bitmap
2022 bitmap_offset = (Bit64s)STANDARD_HEADER_SIZE + (dtoh32(header.specific.catalog) * sizeof(Bit32u));
2023 bitmap_offset += (Bit64s)512 * dtoh32(catalog[extent_index]) * (extent_blocks + bitmap_blocks);
2024 ::lseek(fd, (off_t)bitmap_offset, SEEK_SET);
2025 for (i=0; i<bitmap_blocks; i++) {
2026 ::write(fd, zerobuffer, 512);
2027 }
2028 // Write extent
2029 for (i=0; i<extent_blocks; i++) {
2030 ::write(fd, zerobuffer, 512);
2031 }
2032
2033 delete [] zerobuffer;
2034
2035 update_catalog = 1;
2036 }
2037
2038 bitmap_offset = (Bit64s)STANDARD_HEADER_SIZE + (dtoh32(header.specific.catalog) * sizeof(Bit32u));
2039 bitmap_offset += (Bit64s)512 * dtoh32(catalog[extent_index]) * (extent_blocks + bitmap_blocks);
2040 block_offset = bitmap_offset + ((Bit64s)512 * (bitmap_blocks + extent_offset));
2041
2042 BX_DEBUG(("redolog : bitmap offset is %x", (Bit32u)bitmap_offset));
2043 BX_DEBUG(("redolog : block offset is %x", (Bit32u)block_offset));
2044
2045 // Write block
2046 written = bx_write_image(fd, (off_t)block_offset, (void*)buf, count);
2047
2048 // Write bitmap
2049 if (bitmap_update) {
2050 if (bx_read_image(fd, (off_t)bitmap_offset, bitmap, dtoh32(header.specific.bitmap)) != (ssize_t)dtoh32(header.specific.bitmap)) {
2051 BX_PANIC(("redolog : failed to read bitmap for extent %d", extent_index));
2052 return 0;
2053 }
2054 bitmap_update = 0;
2055 }
2056
2057 // If bloc does not belong to extent yet
2058 if (((bitmap[extent_offset/8] >> (extent_offset%8)) & 0x01) == 0x00) {
2059 bitmap[extent_offset/8] |= 1 << (extent_offset%8);
2060 bx_write_image(fd, (off_t)bitmap_offset, bitmap, dtoh32(header.specific.bitmap));
2061 }
2062
2063 // Write catalog
2064 if (update_catalog) {
2065 // FIXME if mmap
2066 catalog_offset = (Bit64s)STANDARD_HEADER_SIZE + (extent_index * sizeof(Bit32u));
2067
2068 BX_DEBUG(("redolog : writing catalog at offset %x", (Bit32u)catalog_offset));
2069
2070 bx_write_image(fd, (off_t)catalog_offset, &catalog[extent_index], sizeof(Bit32u));
2071 }
2072
2073 if (written >= 0) lseek(512, SEEK_CUR);
2074
2075 return written;
2076 }
2077
check_format(int fd,const char * subtype)2078 int redolog_t::check_format(int fd, const char *subtype)
2079 {
2080 redolog_header_t temp_header;
2081
2082 int res = bx_read_image(fd, 0, &temp_header, sizeof(redolog_header_t));
2083 if (res != STANDARD_HEADER_SIZE) {
2084 return HDIMAGE_READ_ERROR;
2085 }
2086
2087 if (strcmp((char*)temp_header.standard.magic, STANDARD_HEADER_MAGIC) != 0) {
2088 return HDIMAGE_NO_SIGNATURE;
2089 }
2090
2091 if (strcmp((char*)temp_header.standard.type, REDOLOG_TYPE) != 0) {
2092 return HDIMAGE_TYPE_ERROR;
2093 }
2094 if (strcmp((char*)temp_header.standard.subtype, subtype) != 0) {
2095 return HDIMAGE_TYPE_ERROR;
2096 }
2097
2098 if ((dtoh32(temp_header.standard.version) != STANDARD_HEADER_VERSION) &&
2099 (dtoh32(temp_header.standard.version) != STANDARD_HEADER_V1)) {
2100 return HDIMAGE_VERSION_ERROR;
2101 }
2102 return HDIMAGE_FORMAT_OK;
2103 }
2104
2105 #ifdef BXIMAGE
commit(device_image_t * base_image)2106 int redolog_t::commit(device_image_t *base_image)
2107 {
2108 int ret = 0;
2109 Bit32u i;
2110 Bit8u buffer[512];
2111
2112 printf("\nCommitting changes to base image file: [ 0%%]");
2113
2114 for (i = 0; i < dtoh32(header.specific.catalog); i++) {
2115 printf("\x8\x8\x8\x8\x8%3d%%]", (i+1)*100/dtoh32(header.specific.catalog));
2116 fflush(stdout);
2117
2118 if (dtoh32(catalog[i]) != REDOLOG_PAGE_NOT_ALLOCATED) {
2119 Bit64s bitmap_offset;
2120 Bit32u bitmap_size, j;
2121
2122 bitmap_offset = (Bit64s)STANDARD_HEADER_SIZE + (dtoh32(header.specific.catalog) * sizeof(Bit32u));
2123 bitmap_offset += (Bit64s)512 * dtoh32(catalog[i]) * (extent_blocks + bitmap_blocks);
2124
2125 // Read bitmap
2126 bitmap_size = dtoh32(header.specific.bitmap);
2127 if ((Bit32u)bx_read_image(fd, (off_t)bitmap_offset, bitmap, bitmap_size) != bitmap_size) {
2128 ret = -1;
2129 break;
2130 }
2131
2132 for (j = 0; j < dtoh32(header.specific.bitmap); j++) {
2133 Bit32u bit;
2134
2135 for (bit = 0; bit < 8; bit++) {
2136 if ( (bitmap[j] & (1 << bit)) != 0) {
2137 Bit64s base_offset, block_offset;
2138
2139 block_offset = bitmap_offset + ((Bit64s)512 * (bitmap_blocks + ((j * 8) + bit)));
2140
2141 if (bx_read_image(fd, (off_t)block_offset, buffer, 512) != 512) {
2142 ret = -1;
2143 break;
2144 }
2145
2146 base_offset = (Bit64s)i * (dtoh32(header.specific.extent));
2147 base_offset += (Bit64s)512 * ((j * 8) + bit);
2148
2149 if (base_image->lseek(base_offset, SEEK_SET) < 0) {
2150 ret = -1;
2151 break;
2152 }
2153 if (base_image->write(buffer, 512) < 0) {
2154 ret = -1;
2155 break;
2156 }
2157 }
2158 }
2159 }
2160 }
2161 }
2162 return ret;
2163 }
2164 #endif
2165
2166 #ifndef BXIMAGE
save_state(const char * backup_fname)2167 bool redolog_t::save_state(const char *backup_fname)
2168 {
2169 return hdimage_backup_file(fd, backup_fname);
2170 }
2171 #endif
2172
2173 /*** growing_image_t function definitions ***/
2174
growing_image_t()2175 growing_image_t::growing_image_t()
2176 {
2177 redolog = new redolog_t();
2178 }
2179
~growing_image_t()2180 growing_image_t::~growing_image_t()
2181 {
2182 delete redolog;
2183 }
2184
open(const char * _pathname,int flags)2185 int growing_image_t::open(const char* _pathname, int flags)
2186 {
2187 pathname = _pathname;
2188 int filedes = redolog->open(pathname, REDOLOG_SUBTYPE_GROWING, flags);
2189 hd_size = redolog->get_size();
2190 BX_INFO(("'growing' disk opened, growing file is '%s'", pathname));
2191 return filedes;
2192 }
2193
close()2194 void growing_image_t::close()
2195 {
2196 redolog->close();
2197 }
2198
lseek(Bit64s offset,int whence)2199 Bit64s growing_image_t::lseek(Bit64s offset, int whence)
2200 {
2201 return redolog->lseek(offset, whence);
2202 }
2203
read(void * buf,size_t count)2204 ssize_t growing_image_t::read(void* buf, size_t count)
2205 {
2206 char *cbuf = (char*)buf;
2207 size_t n = 0;
2208 ssize_t ret = 0;
2209
2210 memset(buf, 0, count);
2211 while (n < count) {
2212 ret = redolog->read(cbuf, 512);
2213 if (ret < 0) break;
2214 cbuf += 512;
2215 n += 512;
2216 }
2217 return (ret < 0) ? ret : count;
2218 }
2219
write(const void * buf,size_t count)2220 ssize_t growing_image_t::write(const void* buf, size_t count)
2221 {
2222 char *cbuf = (char*)buf;
2223 size_t n = 0;
2224 ssize_t ret = 0;
2225
2226 while (n < count) {
2227 ret = redolog->write(cbuf, 512);
2228 if (ret < 0) break;
2229 cbuf += 512;
2230 n += 512;
2231 }
2232 return (ret < 0) ? ret : count;
2233 }
2234
get_timestamp()2235 Bit32u growing_image_t::get_timestamp()
2236 {
2237 return redolog->get_timestamp();
2238 }
2239
check_format(int fd,Bit64u imgsize)2240 int growing_image_t::check_format(int fd, Bit64u imgsize)
2241 {
2242 return redolog_t::check_format(fd, REDOLOG_SUBTYPE_GROWING);
2243 }
2244
2245 #ifdef BXIMAGE
create_image(const char * pathname,Bit64u size)2246 int growing_image_t::create_image(const char *pathname, Bit64u size)
2247 {
2248 redolog = new redolog_t;
2249 if (redolog->create(pathname, REDOLOG_SUBTYPE_GROWING, size) < 0)
2250 BX_FATAL(("Can't create growing mode image"));
2251 redolog->close();
2252 return 0;
2253 }
2254 #else
save_state(const char * backup_fname)2255 bool growing_image_t::save_state(const char *backup_fname)
2256 {
2257 return redolog->save_state(backup_fname);
2258 }
2259
restore_state(const char * backup_fname)2260 void growing_image_t::restore_state(const char *backup_fname)
2261 {
2262 redolog_t *temp_redolog = new redolog_t();
2263 if (temp_redolog->open(backup_fname, REDOLOG_SUBTYPE_GROWING, O_RDONLY) < 0) {
2264 delete temp_redolog;
2265 BX_PANIC(("Can't open growing image backup '%s'", backup_fname));
2266 return;
2267 } else {
2268 bool okay = (temp_redolog->get_size() == redolog->get_size());
2269 temp_redolog->close();
2270 delete temp_redolog;
2271 if (!okay) {
2272 BX_PANIC(("size reported by backup doesn't match growing disk size"));
2273 return;
2274 }
2275 }
2276 redolog->close();
2277 if (!hdimage_copy_file(backup_fname, pathname)) {
2278 BX_PANIC(("Failed to restore growing image '%s'", pathname));
2279 return;
2280 }
2281 if (device_image_t::open(pathname) < 0) {
2282 BX_PANIC(("Failed to open restored growing image '%s'", pathname));
2283 }
2284 }
2285 #endif
2286
2287 // compare hd_size and modification time of r/o disk and journal
2288
coherency_check(device_image_t * ro_disk,redolog_t * redolog)2289 bool coherency_check(device_image_t *ro_disk, redolog_t *redolog)
2290 {
2291 Bit32u timestamp1, timestamp2;
2292 char buffer[24];
2293
2294 if (ro_disk->hd_size != redolog->get_size()) {
2295 BX_PANIC(("size reported by redolog doesn't match r/o disk size"));
2296 return 0;
2297 }
2298 timestamp1 = ro_disk->get_timestamp();
2299 timestamp2 = redolog->get_timestamp();
2300 if (timestamp2 != 0) {
2301 if (timestamp1 != timestamp2) {
2302 sprintf(buffer, "%02d.%02d.%04d %02d:%02d:%02d", (timestamp2 >> 16) & 0x001f,
2303 (timestamp2 >> 21) & 0x000f, ((timestamp2 >> 25) & 0x007f) + 1980,
2304 (timestamp2 & 0xf800) >> 11, (timestamp2 & 0x07e0) >> 5,
2305 (timestamp2 & 0x001f) << 1);
2306 BX_PANIC(("unexpected modification time of the r/o disk (should be %s)", buffer));
2307 return 0;
2308 }
2309 } else if (timestamp1 != 0) {
2310 redolog->set_timestamp(timestamp1);
2311 }
2312 return 1;
2313 }
2314
2315 /*** undoable_image_t function definitions ***/
2316
undoable_image_t(const char * _redolog_name)2317 undoable_image_t::undoable_image_t(const char* _redolog_name)
2318 {
2319 redolog = new redolog_t();
2320 redolog_name = NULL;
2321 if (_redolog_name != NULL) {
2322 if ((strlen(_redolog_name) > 0) && (strcmp(_redolog_name,"none") != 0)) {
2323 redolog_name = new char[strlen(_redolog_name) + 1];
2324 strcpy(redolog_name, _redolog_name);
2325 }
2326 }
2327 }
2328
~undoable_image_t()2329 undoable_image_t::~undoable_image_t()
2330 {
2331 delete redolog;
2332 delete ro_disk;
2333 }
2334
open(const char * pathname,int flags)2335 int undoable_image_t::open(const char* pathname, int flags)
2336 {
2337 const char* image_mode = NULL;
2338
2339 UNUSED(flags);
2340 if (access(pathname, F_OK) < 0) {
2341 BX_PANIC(("r/o disk image doesn't exist"));
2342 }
2343 if (!hdimage_detect_image_mode(pathname, &image_mode)) {
2344 BX_PANIC(("r/o disk image mode not detected"));
2345 return -1;
2346 } else {
2347 BX_INFO(("base image mode = '%s'", image_mode));
2348 }
2349 ro_disk = DEV_hdimage_init_image(image_mode, 0, NULL);
2350 if (ro_disk == NULL) {
2351 return -1;
2352 }
2353 if (ro_disk->open(pathname, O_RDONLY) < 0)
2354 return -1;
2355
2356 hd_size = ro_disk->hd_size;
2357 if (ro_disk->get_capabilities() & HDIMAGE_HAS_GEOMETRY) {
2358 cylinders = ro_disk->cylinders;
2359 heads = ro_disk->heads;
2360 spt = ro_disk->spt;
2361 caps = HDIMAGE_HAS_GEOMETRY;
2362 } else if (cylinders == 0) {
2363 caps = HDIMAGE_AUTO_GEOMETRY;
2364 }
2365 sect_size = ro_disk->sect_size;
2366
2367 // If not set, we make up the redolog filename from the pathname
2368 if (redolog_name == NULL) {
2369 redolog_name = new char[strlen(pathname) + UNDOABLE_REDOLOG_EXTENSION_LENGTH + 1];
2370 sprintf(redolog_name, "%s%s", pathname, UNDOABLE_REDOLOG_EXTENSION);
2371 }
2372
2373 if (redolog->open(redolog_name, REDOLOG_SUBTYPE_UNDOABLE) < 0) {
2374 if (redolog->create(redolog_name, REDOLOG_SUBTYPE_UNDOABLE, hd_size) < 0) {
2375 BX_PANIC(("Can't open or create redolog '%s'",redolog_name));
2376 return -1;
2377 }
2378 }
2379 if (!coherency_check(ro_disk, redolog)) {
2380 close();
2381 return -1;
2382 }
2383
2384 BX_INFO(("'undoable' disk opened: ro-file is '%s', redolog is '%s'", pathname, redolog_name));
2385
2386 return 0;
2387 }
2388
close()2389 void undoable_image_t::close()
2390 {
2391 redolog->close();
2392 ro_disk->close();
2393
2394 if (redolog_name != NULL)
2395 delete [] redolog_name;
2396 }
2397
lseek(Bit64s offset,int whence)2398 Bit64s undoable_image_t::lseek(Bit64s offset, int whence)
2399 {
2400 redolog->lseek(offset, whence);
2401 return ro_disk->lseek(offset, whence);
2402 }
2403
read(void * buf,size_t count)2404 ssize_t undoable_image_t::read(void* buf, size_t count)
2405 {
2406 char *cbuf = (char*)buf;
2407 size_t n = 0;
2408 ssize_t ret = 0;
2409
2410 while (n < count) {
2411 if ((size_t)redolog->read(cbuf, 512) != 512) {
2412 ret = ro_disk->read(cbuf, 512);
2413 if (ret < 0) break;
2414 }
2415 cbuf += 512;
2416 n += 512;
2417 }
2418 return (ret < 0) ? ret : count;
2419 }
2420
write(const void * buf,size_t count)2421 ssize_t undoable_image_t::write(const void* buf, size_t count)
2422 {
2423 char *cbuf = (char*)buf;
2424 size_t n = 0;
2425 ssize_t ret = 0;
2426
2427 while (n < count) {
2428 ret = redolog->write(cbuf, 512);
2429 if (ret < 0) break;
2430 cbuf += 512;
2431 n += 512;
2432 }
2433 return (ret < 0) ? ret : count;
2434 }
2435
2436 #ifndef BXIMAGE
save_state(const char * backup_fname)2437 bool undoable_image_t::save_state(const char *backup_fname)
2438 {
2439 return redolog->save_state(backup_fname);
2440 }
2441
restore_state(const char * backup_fname)2442 void undoable_image_t::restore_state(const char *backup_fname)
2443 {
2444 redolog_t *temp_redolog = new redolog_t();
2445 if (temp_redolog->open(backup_fname, REDOLOG_SUBTYPE_UNDOABLE, O_RDONLY) < 0) {
2446 delete temp_redolog;
2447 BX_PANIC(("Can't open undoable redolog backup '%s'", backup_fname));
2448 return;
2449 } else {
2450 bool okay = coherency_check(ro_disk, temp_redolog);
2451 temp_redolog->close();
2452 delete temp_redolog;
2453 if (!okay) return;
2454 }
2455 redolog->close();
2456 if (!hdimage_copy_file(backup_fname, redolog_name)) {
2457 BX_PANIC(("Failed to restore undoable redolog '%s'", redolog_name));
2458 return;
2459 } else {
2460 if (redolog->open(redolog_name, REDOLOG_SUBTYPE_UNDOABLE) < 0) {
2461 BX_PANIC(("Can't open restored undoable redolog '%s'", redolog_name));
2462 }
2463 }
2464 }
2465 #endif
2466
2467 /*** volatile_image_t function definitions ***/
2468
volatile_image_t(const char * _redolog_name)2469 volatile_image_t::volatile_image_t(const char* _redolog_name)
2470 {
2471 redolog = new redolog_t();
2472 redolog_temp = NULL;
2473 redolog_name = NULL;
2474 if (_redolog_name != NULL) {
2475 if ((strlen(_redolog_name) > 0) && (strcmp(_redolog_name,"none") != 0)) {
2476 redolog_name = new char[strlen(_redolog_name) + 1];
2477 strcpy(redolog_name, _redolog_name);
2478 }
2479 }
2480 }
2481
~volatile_image_t()2482 volatile_image_t::~volatile_image_t()
2483 {
2484 delete redolog;
2485 delete ro_disk;
2486 }
2487
open(const char * pathname,int flags)2488 int volatile_image_t::open(const char* pathname, int flags)
2489 {
2490 int filedes;
2491 Bit32u timestamp;
2492 const char* image_mode = NULL;
2493
2494 UNUSED(flags);
2495 if (access(pathname, F_OK) < 0) {
2496 BX_PANIC(("r/o disk image doesn't exist"));
2497 }
2498 if (!hdimage_detect_image_mode(pathname, &image_mode)) {
2499 BX_PANIC(("r/o disk image mode not detected"));
2500 return -1;
2501 } else {
2502 BX_INFO(("base image mode = '%s'", image_mode));
2503 }
2504 ro_disk = DEV_hdimage_init_image(image_mode, 0, NULL);
2505 if (ro_disk == NULL) {
2506 return -1;
2507 }
2508 if (ro_disk->open(pathname, O_RDONLY)<0)
2509 return -1;
2510
2511 hd_size = ro_disk->hd_size;
2512 if (ro_disk->get_capabilities() & HDIMAGE_HAS_GEOMETRY) {
2513 cylinders = ro_disk->cylinders;
2514 heads = ro_disk->heads;
2515 spt = ro_disk->spt;
2516 caps = HDIMAGE_HAS_GEOMETRY;
2517 } else if (cylinders == 0) {
2518 caps = HDIMAGE_AUTO_GEOMETRY;
2519 }
2520 sect_size = ro_disk->sect_size;
2521
2522 // If not set, use pathname as template
2523 if (redolog_name == NULL) {
2524 redolog_name = new char[strlen(pathname) + 1];
2525 strcpy(redolog_name, pathname);
2526 }
2527
2528 redolog_temp = new char[strlen(redolog_name) + VOLATILE_REDOLOG_EXTENSION_LENGTH + 1];
2529 sprintf(redolog_temp, "%s%s", redolog_name, VOLATILE_REDOLOG_EXTENSION);
2530
2531 filedes = mkstemp(redolog_temp);
2532
2533 if (filedes < 0) {
2534 BX_PANIC(("Can't create volatile redolog '%s'", redolog_temp));
2535 return -1;
2536 }
2537 if (redolog->create(filedes, REDOLOG_SUBTYPE_VOLATILE, hd_size) < 0) {
2538 BX_PANIC(("Can't create volatile redolog '%s'", redolog_temp));
2539 return -1;
2540 }
2541
2542 #if (!defined(WIN32)) && !BX_WITH_MACOS
2543 // on unix it is legal to delete an open file
2544 unlink(redolog_temp);
2545 #endif
2546
2547 // timestamp required for save/restore support
2548 timestamp = ro_disk->get_timestamp();
2549 redolog->set_timestamp(timestamp);
2550
2551 BX_INFO(("'volatile' disk opened: ro-file is '%s', redolog is '%s'", pathname, redolog_temp));
2552
2553 return 0;
2554 }
2555
close()2556 void volatile_image_t::close()
2557 {
2558 redolog->close();
2559 ro_disk->close();
2560
2561 #if defined(WIN32) || BX_WITH_MACOS
2562 // on non-unix we have to wait till the file is closed to delete it
2563 unlink(redolog_temp);
2564 #endif
2565 if (redolog_temp!=NULL)
2566 delete [] redolog_temp;
2567
2568 if (redolog_name!=NULL)
2569 delete [] redolog_name;
2570 }
2571
lseek(Bit64s offset,int whence)2572 Bit64s volatile_image_t::lseek(Bit64s offset, int whence)
2573 {
2574 redolog->lseek(offset, whence);
2575 return ro_disk->lseek(offset, whence);
2576 }
2577
read(void * buf,size_t count)2578 ssize_t volatile_image_t::read(void* buf, size_t count)
2579 {
2580 char *cbuf = (char*)buf;
2581 size_t n = 0;
2582 ssize_t ret = 0;
2583
2584 while (n < count) {
2585 if ((size_t)redolog->read(cbuf, 512) != 512) {
2586 ret = ro_disk->read(cbuf, 512);
2587 if (ret < 0) break;
2588 }
2589 cbuf += 512;
2590 n += 512;
2591 }
2592 return (ret < 0) ? ret : count;
2593 }
2594
write(const void * buf,size_t count)2595 ssize_t volatile_image_t::write(const void* buf, size_t count)
2596 {
2597 char *cbuf = (char*)buf;
2598 size_t n = 0;
2599 ssize_t ret = 0;
2600
2601 while (n < count) {
2602 ret = redolog->write(cbuf, 512);
2603 if (ret < 0) break;
2604 cbuf += 512;
2605 n += 512;
2606 }
2607 return (ret < 0) ? ret : count;
2608 }
2609
2610 #ifndef BXIMAGE
save_state(const char * backup_fname)2611 bool volatile_image_t::save_state(const char *backup_fname)
2612 {
2613 return redolog->save_state(backup_fname);
2614 }
2615
restore_state(const char * backup_fname)2616 void volatile_image_t::restore_state(const char *backup_fname)
2617 {
2618 redolog_t *temp_redolog = new redolog_t();
2619 if (temp_redolog->open(backup_fname, REDOLOG_SUBTYPE_VOLATILE, O_RDONLY) < 0) {
2620 delete temp_redolog;
2621 BX_PANIC(("Can't open volatile redolog backup '%s'", backup_fname));
2622 return;
2623 } else {
2624 bool okay = coherency_check(ro_disk, temp_redolog);
2625 temp_redolog->close();
2626 delete temp_redolog;
2627 if (!okay) return;
2628 }
2629 redolog->close();
2630 if (!hdimage_copy_file(backup_fname, redolog_temp)) {
2631 BX_PANIC(("Failed to restore volatile redolog '%s'", redolog_temp));
2632 return;
2633 } else {
2634 if (redolog->open(redolog_temp, REDOLOG_SUBTYPE_VOLATILE) < 0) {
2635 BX_PANIC(("Can't open restored volatile redolog '%s'", redolog_temp));
2636 return;
2637 }
2638 }
2639 #if (!defined(WIN32)) && !BX_WITH_MACOS
2640 // on unix it is legal to delete an open file
2641 unlink(redolog_temp);
2642 #endif
2643 }
2644 #endif
2645