- added instructions how to update the online documentation
[bochs-mirror.git] / iodev / hdimage.cc
blobb16d9421b48d88bd5b8130b1c0076d72f1a7cac2
1 /////////////////////////////////////////////////////////////////////////
2 // $Id: hdimage.cc,v 1.16 2008/02/15 22:05:42 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2002 MandrakeSoft S.A.
6 //
7 // MandrakeSoft S.A.
8 // 43, rue d'Aboukir
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 /////////////////////////////////////////////////////////////////////////
28 // Define BX_PLUGGABLE in files that can be compiled into plugins. For
29 // platforms that require a special tag on exported symbols, BX_PLUGGABLE
30 // is used to know when we are exporting symbols and when we are importing.
31 #define BX_PLUGGABLE
33 #define NO_DEVICE_INCLUDES
34 #include "iodev.h"
35 #include "hdimage.h"
37 #if BX_HAVE_SYS_MMAN_H
38 #include <sys/mman.h>
39 #endif
41 #define LOG_THIS bx_devices.pluginHardDrive->
43 /*** base class device_image_t ***/
45 device_image_t::device_image_t()
47 hd_size = 0;
50 /*** default_image_t function definitions ***/
52 int default_image_t::open(const char* pathname)
54 return open(pathname, O_RDWR);
57 int default_image_t::open(const char* pathname, int flags)
59 #ifdef WIN32
60 HANDLE hFile = CreateFile(pathname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL);
61 if (hFile != INVALID_HANDLE_VALUE) {
62 ULARGE_INTEGER FileSize;
63 FileSize.LowPart = GetFileSize(hFile, &FileSize.HighPart);
64 CloseHandle(hFile);
65 if ((FileSize.LowPart != INVALID_FILE_SIZE) || (GetLastError() == NO_ERROR)) {
66 hd_size = FileSize.QuadPart;
67 } else {
68 return -1;
70 } else {
71 return -1;
73 #endif
75 fd = ::open(pathname, flags
76 #ifdef O_BINARY
77 | O_BINARY
78 #endif
81 if (fd < 0) {
82 return fd;
85 #ifndef WIN32
86 /* look at size of image file to calculate disk geometry */
87 struct stat stat_buf;
88 int ret = fstat(fd, &stat_buf);
89 if (ret) {
90 BX_PANIC(("fstat() returns error!"));
92 hd_size = (Bit64u)stat_buf.st_size;
93 #endif
94 if ((hd_size % 512) != 0) {
95 BX_PANIC(("size of disk image must be multiple of 512 bytes"));
98 return fd;
101 void default_image_t::close()
103 if (fd > -1) {
104 ::close(fd);
108 Bit64s default_image_t::lseek(Bit64s offset, int whence)
110 return (Bit64s)::lseek(fd, (off_t)offset, whence);
113 ssize_t default_image_t::read(void* buf, size_t count)
115 return ::read(fd, (char*) buf, count);
118 ssize_t default_image_t::write(const void* buf, size_t count)
120 return ::write(fd, (char*) buf, count);
123 char increment_string(char *str, int diff)
125 // find the last character of the string, and increment it.
126 char *p = str;
127 while (*p != 0) p++;
128 BX_ASSERT(p>str); // choke on zero length strings
129 p--; // point to last character of the string
130 (*p) += diff; // increment to next/previous ascii code.
131 BX_DEBUG(("increment string returning '%s'", str));
132 return (*p);
135 /*** concat_image_t function definitions ***/
137 concat_image_t::concat_image_t()
139 fd = -1;
142 void concat_image_t::increment_string(char *str)
144 ::increment_string(str, +1);
147 int concat_image_t::open(const char* pathname0)
149 char *pathname = strdup(pathname0);
150 BX_DEBUG(("concat_image_t.open"));
151 Bit64s start_offset = 0;
152 for (int i=0; i<BX_CONCAT_MAX_IMAGES; i++) {
153 fd_table[i] = ::open(pathname, O_RDWR
154 #ifdef O_BINARY
155 | O_BINARY
156 #endif
158 if (fd_table[i] < 0) {
159 // open failed.
160 // if no FD was opened successfully, return -1 (fail).
161 if (i==0) return -1;
162 // otherwise, it only means that all images in the series have
163 // been opened. Record the number of fds opened successfully.
164 maxfd = i;
165 break;
167 BX_DEBUG(("concat_image: open image %s, fd[%d] = %d", pathname, i, fd_table[i]));
168 /* look at size of image file to calculate disk geometry */
169 struct stat stat_buf;
170 int ret = fstat(fd_table[i], &stat_buf);
171 if (ret) {
172 BX_PANIC(("fstat() returns error!"));
174 #ifdef S_ISBLK
175 if (S_ISBLK(stat_buf.st_mode)) {
176 BX_PANIC(("block devices should REALLY NOT be used as concat images"));
178 #endif
179 if ((stat_buf.st_size % 512) != 0) {
180 BX_PANIC(("size of disk image must be multiple of 512 bytes"));
182 length_table[i] = stat_buf.st_size;
183 start_offset_table[i] = start_offset;
184 start_offset += stat_buf.st_size;
185 increment_string(pathname);
187 // start up with first image selected
188 index = 0;
189 fd = fd_table[0];
190 thismin = 0;
191 thismax = length_table[0]-1;
192 seek_was_last_op = 0;
193 hd_size = start_offset;
194 return 0; // success.
197 void concat_image_t::close()
199 BX_DEBUG(("concat_image_t.close"));
200 if (fd > -1) {
201 ::close(fd);
205 Bit64s concat_image_t::lseek(Bit64s offset, int whence)
207 if ((offset % 512) != 0)
208 BX_PANIC(("lseek HD with offset not multiple of 512"));
209 BX_DEBUG(("concat_image_t.lseek(%d)", whence));
210 // is this offset in this disk image?
211 if (offset < thismin) {
212 // no, look at previous images
213 for (int i=index-1; i>=0; i--) {
214 if (offset >= start_offset_table[i]) {
215 index = i;
216 fd = fd_table[i];
217 thismin = start_offset_table[i];
218 thismax = thismin + length_table[i] - 1;
219 BX_DEBUG(("concat_image_t.lseek to earlier image, index=%d", index));
220 break;
223 } else if (offset > thismax) {
224 // no, look at later images
225 for (int i=index+1; i<maxfd; i++) {
226 if (offset < start_offset_table[i] + length_table[i]) {
227 index = i;
228 fd = fd_table[i];
229 thismin = start_offset_table[i];
230 thismax = thismin + length_table[i] - 1;
231 BX_DEBUG(("concat_image_t.lseek to earlier image, index=%d", index));
232 break;
236 // now offset should be within the current image.
237 offset -= start_offset_table[index];
238 if (offset < 0 || offset >= length_table[index]) {
239 BX_PANIC(("concat_image_t.lseek to byte %ld failed", (long)offset));
240 return -1;
243 seek_was_last_op = 1;
244 return (Bit64s)::lseek(fd, (off_t)offset, whence);
247 ssize_t concat_image_t::read(void* buf, size_t count)
249 if (bx_dbg.disk)
250 BX_DEBUG(("concat_image_t.read %ld bytes", (long)count));
251 // notice if anyone does sequential read or write without seek in between.
252 // This can be supported pretty easily, but needs additional checks for
253 // end of a partial image.
254 if (!seek_was_last_op)
255 BX_PANIC(("no seek before read"));
256 return ::read(fd, (char*) buf, count);
259 ssize_t concat_image_t::write(const void* buf, size_t count)
261 BX_DEBUG(("concat_image_t.write %ld bytes", (long)count));
262 // notice if anyone does sequential read or write without seek in between.
263 // This can be supported pretty easily, but needs additional checks for
264 // end of a partial image.
265 if (!seek_was_last_op)
266 BX_PANIC(("no seek before write"));
267 return ::write(fd, (char*) buf, count);
270 /*** sparse_image_t function definitions ***/
272 sparse_image_t::sparse_image_t ()
274 fd = -1;
275 pathname = NULL;
276 #ifdef _POSIX_MAPPED_FILES
277 mmap_header = NULL;
278 #endif
279 pagetable = NULL;
283 void showpagetable(Bit32u * pagetable, size_t numpages)
285 printf("Non null pages: ");
286 for (int i = 0; i < numpages; i++)
288 if (pagetable[i] != 0xffffffff)
290 printf("%d ", i);
293 printf("\n");
297 void sparse_image_t::read_header()
299 BX_ASSERT(sizeof(header) == SPARSE_HEADER_SIZE);
301 int ret = ::read(fd, &header, sizeof(header));
303 if (-1 == ret)
305 panic(strerror(errno));
308 if (sizeof(header) != ret)
310 panic("could not read entire header");
313 if (dtoh32(header.magic) != SPARSE_HEADER_MAGIC)
315 panic("failed header magic check");
318 if ((dtoh32(header.version) != SPARSE_HEADER_VERSION) &&
319 (dtoh32(header.version) != SPARSE_HEADER_V1))
321 panic("unknown version in header");
324 pagesize = dtoh32(header.pagesize);
325 Bit32u numpages = dtoh32(header.numpages);
327 total_size = pagesize;
328 total_size *= numpages;
330 pagesize_shift = 0;
331 while ((pagesize >> pagesize_shift) > 1) pagesize_shift++;
333 if ((Bit32u)(1 << pagesize_shift) != pagesize)
335 panic("failed block size header check");
338 pagesize_mask = pagesize - 1;
340 size_t preamble_size = (sizeof(Bit32u) * numpages) + sizeof(header);
341 data_start = 0;
342 while ((size_t)data_start < preamble_size) data_start += pagesize;
344 bx_bool did_mmap = 0;
346 #ifdef _POSIX_MAPPED_FILES
347 // Try to memory map from the beginning of the file (0 is trivially a page multiple)
348 void * mmap_header = mmap(NULL, preamble_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
349 if (mmap_header == MAP_FAILED)
351 BX_INFO(("failed to mmap sparse disk file - using conventional file access"));
352 mmap_header = NULL;
354 else
356 mmap_length = preamble_size;
357 did_mmap = 1;
358 pagetable = ((Bit32u *) (((Bit8u *) mmap_header) + sizeof(header)));
359 system_pagesize_mask = getpagesize() - 1;
361 #endif
363 if (!did_mmap)
365 pagetable = new Bit32u[numpages];
367 if (pagetable == NULL)
369 panic("could not allocate memory for sparse disk block table");
372 ret = ::read(fd, pagetable, sizeof(Bit32u) * numpages);
374 if (-1 == ret)
376 panic(strerror(errno));
379 if ((int)(sizeof(Bit32u) * numpages) != ret)
381 panic("could not read entire block table");
386 int sparse_image_t::open (const char* pathname0)
388 pathname = strdup(pathname0);
389 BX_DEBUG(("sparse_image_t.open"));
391 fd = ::open(pathname, O_RDWR
392 #ifdef O_BINARY
393 | O_BINARY
394 #endif
397 if (fd < 0)
399 return -1; // open failed
401 BX_DEBUG(("sparse_image: open image %s", pathname));
403 read_header();
405 struct stat stat_buf;
406 if (fstat(fd, &stat_buf) != 0) panic(("fstat() returns error!"));
408 underlying_filesize = stat_buf.st_size;
410 if ((underlying_filesize % pagesize) != 0)
411 panic("size of sparse disk image is not multiple of page size");
413 underlying_current_filepos = 0;
414 if (-1 == ::lseek(fd, 0, SEEK_SET))
415 panic("error while seeking to start of file");
417 lseek(0, SEEK_SET);
419 //showpagetable(pagetable, header.numpages);
421 char * parentpathname = strdup(pathname);
422 char lastchar = ::increment_string(parentpathname, -1);
424 if ((lastchar >= '0') && (lastchar <= '9'))
426 struct stat stat_buf;
427 if (0 == stat(parentpathname, &stat_buf))
429 parent_image = new sparse_image_t();
430 int ret = parent_image->open(parentpathname);
431 if (ret != 0) return ret;
432 if ( (parent_image->pagesize != pagesize)
433 || (parent_image->total_size != total_size))
435 panic("child drive image does not have same page count/page size configuration");
440 if (parentpathname != NULL) free(parentpathname);
442 if (dtoh32(header.version) == SPARSE_HEADER_VERSION) {
443 hd_size = dtoh64(header.disk);
446 return 0; // success
449 void sparse_image_t::close()
451 BX_DEBUG(("concat_image_t.close"));
452 if (pathname != NULL)
454 free(pathname);
456 #ifdef _POSIX_MAPPED_FILES
457 if (mmap_header != NULL)
459 int ret = munmap(mmap_header, mmap_length);
460 if (ret != 0)
461 BX_INFO(("failed to un-memory map sparse disk file"));
463 pagetable = NULL; // We didn't malloc it
464 #endif
465 if (fd > -1) {
466 ::close(fd);
468 if (pagetable != NULL)
470 delete [] pagetable;
472 if (parent_image != NULL)
474 delete parent_image;
478 Bit64s sparse_image_t::lseek(Bit64s offset, int whence)
480 //showpagetable(pagetable, header.numpages);
482 if ((offset % 512) != 0)
483 BX_PANIC(("lseek HD with offset not multiple of 512"));
484 if (whence != SEEK_SET)
485 BX_PANIC(("lseek HD with whence not SEEK_SET"));
487 BX_DEBUG(("sparse_image_t.lseek(%d)", whence));
489 if (offset > total_size)
491 BX_PANIC(("sparse_image_t.lseek to byte %ld failed", (long)offset));
492 return -1;
495 //printf("Seeking to position %ld\n", (long) offset);
497 set_virtual_page((Bit32u)(offset >> pagesize_shift));
498 position_page_offset = (Bit32u)(offset & pagesize_mask);
500 return 0;
503 inline Bit64s sparse_image_t::get_physical_offset()
505 Bit64s physical_offset = data_start;
506 physical_offset += ((Bit64s)position_physical_page << pagesize_shift);
507 physical_offset += position_page_offset;
508 return physical_offset;
511 void sparse_image_t::set_virtual_page(Bit32u new_virtual_page)
513 position_virtual_page = new_virtual_page;
514 position_physical_page = dtoh32(pagetable[position_virtual_page]);
517 ssize_t sparse_image_t::read_page_fragment(Bit32u read_virtual_page, Bit32u read_page_offset, size_t read_size, void * buf)
519 if (read_virtual_page != position_virtual_page)
521 set_virtual_page(read_virtual_page);
524 position_page_offset = read_page_offset;
526 if (position_physical_page == SPARSE_PAGE_NOT_ALLOCATED)
528 if (parent_image != NULL)
530 return parent_image->read_page_fragment(read_virtual_page, read_page_offset, read_size, buf);
532 else
534 memset(buf, 0, read_size);
537 else
539 Bit64s physical_offset = get_physical_offset();
541 if (physical_offset != underlying_current_filepos)
543 off_t ret = ::lseek(fd, (off_t)physical_offset, SEEK_SET);
544 // underlying_current_filepos update deferred
545 if (ret == -1)
546 panic(strerror(errno));
549 //printf("Reading %s at position %ld size %d\n", pathname, (long) physical_offset, (long) read_size);
550 ssize_t readret = ::read(fd, buf, read_size);
552 if (readret == -1)
554 panic(strerror(errno));
557 if ((size_t)readret != read_size)
559 panic("could not read block contents from file");
562 underlying_current_filepos = physical_offset + read_size;
565 return read_size;
568 ssize_t sparse_image_t::read(void* buf, size_t count)
570 //showpagetable(pagetable, header.numpages);
571 ssize_t total_read = 0;
573 if (bx_dbg.disk)
574 BX_DEBUG(("sparse_image_t.read %ld bytes", (long)count));
576 while (count != 0)
578 size_t can_read = pagesize - position_page_offset;
579 if (count < can_read) can_read = count;
581 BX_ASSERT (can_read != 0);
583 size_t was_read = read_page_fragment(position_virtual_page, position_page_offset, can_read, buf);
585 BX_ASSERT(was_read == can_read);
587 total_read += can_read;
589 position_page_offset += can_read;
590 if (position_page_offset == pagesize)
592 position_page_offset = 0;
593 set_virtual_page(position_virtual_page + 1);
596 BX_ASSERT(position_page_offset < pagesize);
598 buf = (((Bit8u *) buf) + can_read);
599 count -= can_read;
602 return total_read;
605 void sparse_image_t::panic(const char * message)
607 char buffer[1024];
608 if (message == NULL)
610 snprintf(buffer, sizeof(buffer), "error with sparse disk image %s", pathname);
612 else
614 snprintf(buffer, sizeof(buffer), "error with sparse disk image %s - %s", pathname, message);
616 BX_PANIC((buffer));
619 ssize_t sparse_image_t::write (const void* buf, size_t count)
621 //showpagetable(pagetable, header.numpages);
623 ssize_t total_written = 0;
625 Bit32u update_pagetable_start = position_virtual_page;
626 Bit32u update_pagetable_count = 0;
628 if (bx_dbg.disk)
629 BX_DEBUG(("sparse_image_t.write %ld bytes", (long)count));
631 while (count != 0)
633 size_t can_write = pagesize - position_page_offset;
634 if (count < can_write) can_write = count;
636 BX_ASSERT (can_write != 0);
638 if (position_physical_page == SPARSE_PAGE_NOT_ALLOCATED)
640 // We just add on another page at the end of the file
641 // Reclamation, compaction etc should currently be done off-line
643 Bit64s data_size = underlying_filesize - data_start;
644 BX_ASSERT((data_size % pagesize) == 0);
646 Bit32u data_size_pages = (Bit32u)(data_size / pagesize);
647 Bit32u next_data_page = data_size_pages;
649 pagetable[position_virtual_page] = htod32(next_data_page);
650 position_physical_page = next_data_page;
652 Bit64s page_file_start = data_start + ((Bit64s)position_physical_page << pagesize_shift);
654 if (parent_image != NULL)
656 // If we have a parent, we must merge our portion with the parent
657 void *writebuffer = NULL;
659 if (can_write == pagesize)
661 writebuffer = (void *) buf;
663 else
665 writebuffer = malloc(pagesize);
666 if (writebuffer == NULL)
667 panic("Cannot allocate sufficient memory for page-merge in write");
669 // Read entire page - could optimize, but simple for now
670 parent_image->read_page_fragment(position_virtual_page, 0, pagesize, writebuffer);
672 void *dest_start = ((Bit8u *) writebuffer) + position_page_offset;
673 memcpy(dest_start, buf, can_write);
676 int ret = (int)::lseek(fd, page_file_start, SEEK_SET);
677 // underlying_current_filepos update deferred
678 if (ret == -1) panic(strerror(errno));
680 ret = ::write(fd, writebuffer, pagesize);
681 if (ret == -1) panic(strerror(errno));
683 if (pagesize != (Bit32u)ret) panic("failed to write entire merged page to disk");
685 if (can_write != pagesize)
687 free(writebuffer);
690 else
692 // We need to write a zero page because read has been returning zeroes
693 // We seek as close to the page end as possible, and then write a little
694 // This produces a sparse file which has blanks
695 // Also very quick, even when pagesize is massive
696 int ret = (int)::lseek(fd, page_file_start + pagesize - 4, SEEK_SET);
697 // underlying_current_filepos update deferred
698 if (ret == -1) panic(strerror(errno));
700 Bit32u zero = 0;
701 ret = ::write(fd, &zero, 4);
702 if (ret == -1) panic(strerror(errno));
704 if (ret != 4) panic("failed to write entire blank page to disk");
707 update_pagetable_count = (position_virtual_page - update_pagetable_start) + 1;
708 underlying_filesize = underlying_current_filepos = page_file_start + pagesize;
711 BX_ASSERT(position_physical_page != SPARSE_PAGE_NOT_ALLOCATED);
713 Bit64s physical_offset = get_physical_offset();
715 if (physical_offset != underlying_current_filepos)
717 off_t ret = ::lseek(fd, (off_t)physical_offset, SEEK_SET);
718 // underlying_current_filepos update deferred
719 if (ret == -1)
720 panic(strerror(errno));
723 //printf("Writing at position %ld size %d\n", (long) physical_offset, can_write);
724 ssize_t writeret = ::write(fd, buf, can_write);
726 if (writeret == -1)
728 panic(strerror(errno));
731 if ((size_t)writeret != can_write)
733 panic("could not write block contents to file");
736 underlying_current_filepos = physical_offset + can_write;
738 total_written += can_write;
740 position_page_offset += can_write;
741 if (position_page_offset == pagesize)
743 position_page_offset = 0;
744 set_virtual_page(position_virtual_page + 1);
747 BX_ASSERT(position_page_offset < pagesize);
749 buf = (((Bit8u *) buf) + can_write);
750 count -= can_write;
753 if (update_pagetable_count != 0)
755 bx_bool done = 0;
756 off_t pagetable_write_from = sizeof(header) + (sizeof(Bit32u) * update_pagetable_start);
757 size_t write_bytecount = update_pagetable_count * sizeof(Bit32u);
759 #ifdef _POSIX_MAPPED_FILES
760 if (mmap_header != NULL)
762 // Sync from the beginning of the page
763 size_t system_page_offset = pagetable_write_from & system_pagesize_mask;
764 void *start = ((Bit8u *) mmap_header + pagetable_write_from - system_page_offset);
766 int ret = msync(start, system_page_offset + write_bytecount, MS_ASYNC);
768 if (ret != 0)
769 panic(strerror(errno));
771 done = 1;
773 #endif
775 if (!done)
777 int ret = (int)::lseek(fd, pagetable_write_from, SEEK_SET);
778 // underlying_current_filepos update deferred
779 if (ret == -1) panic(strerror(errno));
781 //printf("Writing header at position %ld size %ld\n", (long) pagetable_write_from, (long) write_bytecount);
782 ret = ::write(fd, &pagetable[update_pagetable_start], write_bytecount);
783 if (ret == -1) panic(strerror(errno));
784 if ((size_t)ret != write_bytecount) panic("could not write entire updated block header");
786 underlying_current_filepos = pagetable_write_from + write_bytecount;
790 return total_written;
793 #if DLL_HD_SUPPORT
795 /*** dll_image_t function definitions ***/
798 function vdisk_open(path:PChar;numclusters,clustersize:integer):integer;
799 procedure vdisk_read(vunit:integer;blk:integer;var buf:TBlock);
800 procedure vdisk_write(vunit:integer;blk:integer;var buf:TBlock);
801 procedure vdisk_close(vunit:integer);
804 HINSTANCE hlib_vdisk = 0;
806 int (*vdisk_open) (const char *path,int numclusters,int clustersize);
807 void (*vdisk_read) (int vunit,int blk,void *buf);
808 void (*vdisk_write) (int vunit,int blk,const void *buf);
809 void (*vdisk_close) (int vunit);
811 int dll_image_t::open (const char* pathname)
813 if (hlib_vdisk == 0) {
814 hlib_vdisk = LoadLibrary("vdisk.dll");
815 if (hlib_vdisk != 0) {
816 vdisk_read = (void (*)(int,int,void*)) GetProcAddress(hlib_vdisk,"vdisk_read");
817 vdisk_write = (void (*)(int,int,const void*)) GetProcAddress(hlib_vdisk,"vdisk_write");
818 vdisk_open = (int (*)(const char *,int,int)) GetProcAddress(hlib_vdisk,"vdisk_open");
819 vdisk_close = (void (*)(int)) GetProcAddress(hlib_vdisk,"vdisk_close");
822 if (hlib_vdisk != 0) {
823 vunit = vdisk_open(pathname,0x10000,64);
824 vblk = 0;
825 } else {
826 vunit = -2;
828 return vunit;
831 void dll_image_t::close ()
833 if (vunit >= 0 && hlib_vdisk != 0) {
834 vdisk_close(vunit);
838 Bit64s dll_image_t::lseek(Bit64s offset, int whence)
840 vblk = (int)(offset >> 9);
841 return 0;
844 ssize_t dll_image_t::read (void* buf, size_t count)
846 if (vunit >= 0 && hlib_vdisk != 0) {
847 vdisk_read(vunit,vblk,buf);
848 return count;
849 } else {
850 return -1;
854 ssize_t dll_image_t::write (const void* buf, size_t count)
856 if (vunit >= 0 && hlib_vdisk != 0) {
857 vdisk_write(vunit,vblk,buf);
858 return count;
859 } else {
860 return -1;
863 #endif // DLL_HD_SUPPORT
865 // redolog implementation
866 redolog_t::redolog_t()
868 fd = -1;
869 catalog = NULL;
870 bitmap = NULL;
871 extent_index = (Bit32u)0;
872 extent_offset = (Bit32u)0;
873 extent_next = (Bit32u)0;
876 void redolog_t::print_header()
878 BX_INFO(("redolog : Standard Header : magic='%s', type='%s', subtype='%s', version = %d.%d",
879 header.standard.magic, header.standard.type, header.standard.subtype,
880 dtoh32(header.standard.version)/0x10000,
881 dtoh32(header.standard.version)%0x10000));
882 if (dtoh32(header.standard.version) == STANDARD_HEADER_VERSION) {
883 BX_INFO(("redolog : Specific Header : #entries=%d, bitmap size=%d, exent size = %d disk size = " FMT_LL "d",
884 dtoh32(header.specific.catalog),
885 dtoh32(header.specific.bitmap),
886 dtoh32(header.specific.extent),
887 dtoh64(header.specific.disk)));
888 } else if (dtoh32(header.standard.version) == STANDARD_HEADER_V1) {
889 redolog_header_v1_t header_v1;
890 memcpy(&header_v1, &header, STANDARD_HEADER_SIZE);
891 BX_INFO(("redolog : Specific Header : #entries=%d, bitmap size=%d, exent size = %d disk size = " FMT_LL "d",
892 dtoh32(header_v1.specific.catalog),
893 dtoh32(header_v1.specific.bitmap),
894 dtoh32(header_v1.specific.extent),
895 dtoh64(header_v1.specific.disk)));
899 int redolog_t::make_header(const char* type, Bit64u size)
901 Bit32u entries, extent_size, bitmap_size;
902 Bit64u maxsize;
903 Bit32u flip=0;
905 // Set standard header values
906 strcpy((char*)header.standard.magic, STANDARD_HEADER_MAGIC);
907 strcpy((char*)header.standard.type, REDOLOG_TYPE);
908 strcpy((char*)header.standard.subtype, type);
909 header.standard.version = htod32(STANDARD_HEADER_VERSION);
910 header.standard.header = htod32(STANDARD_HEADER_SIZE);
912 entries = 512;
913 bitmap_size = 1;
915 // Compute #entries and extent size values
916 do {
917 extent_size = 8 * bitmap_size * 512;
919 header.specific.catalog = htod32(entries);
920 header.specific.bitmap = htod32(bitmap_size);
921 header.specific.extent = htod32(extent_size);
923 maxsize = (Bit64u)entries * (Bit64u)extent_size;
925 flip++;
927 if(flip&0x01) bitmap_size *= 2;
928 else entries *= 2;
929 } while (maxsize < size);
931 header.specific.disk = htod64(size);
933 print_header();
935 catalog = (Bit32u*)malloc(dtoh32(header.specific.catalog) * sizeof(Bit32u));
936 bitmap = (Bit8u*)malloc(dtoh32(header.specific.bitmap));
938 if ((catalog == NULL) || (bitmap==NULL))
939 BX_PANIC(("redolog : could not malloc catalog or bitmap"));
941 for (Bit32u i=0; i<dtoh32(header.specific.catalog); i++)
942 catalog[i] = htod32(REDOLOG_PAGE_NOT_ALLOCATED);
944 bitmap_blocs = 1 + (dtoh32(header.specific.bitmap) - 1) / 512;
945 extent_blocs = 1 + (dtoh32(header.specific.extent) - 1) / 512;
947 BX_DEBUG(("redolog : each bitmap is %d blocs", bitmap_blocs));
948 BX_DEBUG(("redolog : each extent is %d blocs", extent_blocs));
950 return 0;
953 int redolog_t::create(const char* filename, const char* type, Bit64u size)
955 BX_INFO(("redolog : creating redolog %s", filename));
957 int filedes = ::open(filename, O_RDWR | O_CREAT | O_TRUNC
958 #ifdef O_BINARY
959 | O_BINARY
960 #endif
961 , S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP);
963 return create(filedes, type, size);
966 int redolog_t::create(int filedes, const char* type, Bit64u size)
968 fd = filedes;
970 if (fd < 0)
972 return -1; // open failed
975 if (make_header(type, size) < 0)
977 return -1;
980 // Write header
981 ::write(fd, &header, dtoh32(header.standard.header));
983 // Write catalog
984 // FIXME could mmap
985 ::write(fd, catalog, dtoh32(header.specific.catalog) * sizeof (Bit32u));
987 return 0;
990 int redolog_t::open(const char* filename, const char *type)
992 fd = ::open(filename, O_RDWR
993 #ifdef O_BINARY
994 | O_BINARY
995 #endif
997 if (fd < 0)
999 BX_INFO(("redolog : could not open image %s", filename));
1000 // open failed.
1001 return -1;
1003 BX_INFO(("redolog : open image %s", filename));
1005 int res = ::read(fd, &header, sizeof(header));
1006 if (res != STANDARD_HEADER_SIZE)
1008 BX_PANIC(("redolog : could not read header"));
1009 return -1;
1012 print_header();
1014 if (strcmp((char*)header.standard.magic, STANDARD_HEADER_MAGIC) != 0)
1016 BX_PANIC(("redolog : Bad header magic"));
1017 return -1;
1020 if (strcmp((char*)header.standard.type, REDOLOG_TYPE) != 0)
1022 BX_PANIC(("redolog : Bad header type"));
1023 return -1;
1025 if (strcmp((char*)header.standard.subtype, type) != 0)
1027 BX_PANIC(("redolog : Bad header subtype"));
1028 return -1;
1031 if ((dtoh32(header.standard.version) != STANDARD_HEADER_VERSION) &&
1032 (dtoh32(header.standard.version) != STANDARD_HEADER_V1))
1034 BX_PANIC(("redolog : Bad header version"));
1035 return -1;
1038 if (dtoh32(header.standard.version) == STANDARD_HEADER_V1) {
1039 redolog_header_v1_t header_v1;
1041 memcpy(&header_v1, &header, STANDARD_HEADER_SIZE);
1042 header.specific.disk = header_v1.specific.disk;
1045 catalog = (Bit32u*)malloc(dtoh32(header.specific.catalog) * sizeof(Bit32u));
1047 // FIXME could mmap
1048 ::lseek(fd,dtoh32(header.standard.header),SEEK_SET);
1049 res = ::read(fd, catalog, dtoh32(header.specific.catalog) * sizeof(Bit32u));
1051 if (res != (ssize_t)(dtoh32(header.specific.catalog) * sizeof(Bit32u)))
1053 BX_PANIC(("redolog : could not read catalog %d=%d",res, dtoh32(header.specific.catalog)));
1054 return -1;
1057 // check last used extent
1058 extent_next = 0;
1059 for (Bit32u i=0; i < dtoh32(header.specific.catalog); i++)
1061 if (dtoh32(catalog[i]) != REDOLOG_PAGE_NOT_ALLOCATED)
1063 if (dtoh32(catalog[i]) >= extent_next)
1064 extent_next = dtoh32(catalog[i]) + 1;
1067 BX_INFO(("redolog : next extent will be at index %d",extent_next));
1069 // memory used for storing bitmaps
1070 bitmap = (Bit8u *)malloc(dtoh32(header.specific.bitmap));
1072 bitmap_blocs = 1 + (dtoh32(header.specific.bitmap) - 1) / 512;
1073 extent_blocs = 1 + (dtoh32(header.specific.extent) - 1) / 512;
1075 BX_DEBUG(("redolog : each bitmap is %d blocs", bitmap_blocs));
1076 BX_DEBUG(("redolog : each extent is %d blocs", extent_blocs));
1078 return 0;
1081 void redolog_t::close()
1083 if (fd >= 0)
1084 ::close(fd);
1086 if (catalog != NULL)
1087 free(catalog);
1089 if (bitmap != NULL)
1090 free(bitmap);
1093 Bit64u redolog_t::get_size()
1095 return dtoh64(header.specific.disk);
1098 Bit64s redolog_t::lseek(Bit64s offset, int whence)
1100 if ((offset % 512) != 0) {
1101 BX_PANIC(("redolog : lseek HD with offset not multiple of 512"));
1102 return -1;
1104 if (whence != SEEK_SET) {
1105 BX_PANIC(("redolog : lseek HD with whence not SEEK_SET"));
1106 return -1;
1108 if (offset > (Bit64s)dtoh64(header.specific.disk))
1110 BX_PANIC(("redolog : lseek to byte %ld failed", (long)offset));
1111 return -1;
1114 extent_index = (Bit32u)(offset / dtoh32(header.specific.extent));
1115 extent_offset = (Bit32u)((offset % dtoh32(header.specific.extent)) / 512);
1117 BX_DEBUG(("redolog : lseeking extent index %d, offset %d",extent_index, extent_offset));
1119 return offset;
1122 ssize_t redolog_t::read(void* buf, size_t count)
1124 Bit64s bloc_offset, bitmap_offset;
1126 if (count != 512)
1127 BX_PANIC(("redolog : read HD with count not 512"));
1129 BX_DEBUG(("redolog : reading index %d, mapping to %d", extent_index, dtoh32(catalog[extent_index])));
1131 if (dtoh32(catalog[extent_index]) == REDOLOG_PAGE_NOT_ALLOCATED)
1133 // page not allocated
1134 return 0;
1137 bitmap_offset = (Bit64s)STANDARD_HEADER_SIZE + (dtoh32(header.specific.catalog) * sizeof(Bit32u));
1138 bitmap_offset += (Bit64s)512 * dtoh32(catalog[extent_index]) * (extent_blocs + bitmap_blocs);
1139 bloc_offset = bitmap_offset + ((Bit64s)512 * (bitmap_blocs + extent_offset));
1141 BX_DEBUG(("redolog : bitmap offset is %x", (Bit32u)bitmap_offset));
1142 BX_DEBUG(("redolog : bloc offset is %x", (Bit32u)bloc_offset));
1144 // FIXME if same extent_index as before we can skip bitmap read
1146 ::lseek(fd, (off_t)bitmap_offset, SEEK_SET);
1148 if (::read(fd, bitmap, dtoh32(header.specific.bitmap)) != (ssize_t)dtoh32(header.specific.bitmap))
1150 BX_PANIC(("redolog : failed to read bitmap for extent %d", extent_index));
1151 return 0;
1154 if (((bitmap[extent_offset/8] >> (extent_offset%8)) & 0x01) == 0x00)
1156 BX_DEBUG(("read not in redolog"));
1158 // bitmap says bloc not in reloglog
1159 return 0;
1162 ::lseek(fd, (off_t)bloc_offset, SEEK_SET);
1164 return (::read(fd, buf, count));
1167 ssize_t redolog_t::write(const void* buf, size_t count)
1169 Bit32u i;
1170 Bit64s bloc_offset, bitmap_offset, catalog_offset;
1171 ssize_t written;
1172 bx_bool update_catalog = 0;
1174 if (count != 512)
1175 BX_PANIC(("redolog : write HD with count not 512"));
1177 BX_DEBUG(("redolog : writing index %d, mapping to %d", extent_index, dtoh32(catalog[extent_index])));
1178 if (dtoh32(catalog[extent_index]) == REDOLOG_PAGE_NOT_ALLOCATED)
1180 if (extent_next >= dtoh32(header.specific.catalog))
1182 BX_PANIC(("redolog : can't allocate new extent... catalog is full"));
1183 return 0;
1186 BX_DEBUG(("redolog : allocating new extent at %d", extent_next));
1188 // Extent not allocated, allocate new
1189 catalog[extent_index] = htod32(extent_next);
1191 extent_next += 1;
1193 char *zerobuffer = (char*)malloc(512);
1194 memset(zerobuffer, 0, 512);
1196 // Write bitmap
1197 bitmap_offset = (Bit64s)STANDARD_HEADER_SIZE + (dtoh32(header.specific.catalog) * sizeof(Bit32u));
1198 bitmap_offset += (Bit64s)512 * dtoh32(catalog[extent_index]) * (extent_blocs + bitmap_blocs);
1199 ::lseek(fd, (off_t)bitmap_offset, SEEK_SET);
1200 for (i=0; i<bitmap_blocs; i++)
1202 ::write(fd, zerobuffer, 512);
1204 // Write extent
1205 for (i=0; i<extent_blocs; i++)
1207 ::write(fd, zerobuffer, 512);
1210 free(zerobuffer);
1212 update_catalog = 1;
1215 bitmap_offset = (Bit64s)STANDARD_HEADER_SIZE + (dtoh32(header.specific.catalog) * sizeof(Bit32u));
1216 bitmap_offset += (Bit64s)512 * dtoh32(catalog[extent_index]) * (extent_blocs + bitmap_blocs);
1217 bloc_offset = bitmap_offset + ((Bit64s)512 * (bitmap_blocs + extent_offset));
1219 BX_DEBUG(("redolog : bitmap offset is %x", (Bit32u)bitmap_offset));
1220 BX_DEBUG(("redolog : bloc offset is %x", (Bit32u)bloc_offset));
1222 // Write bloc
1223 ::lseek(fd, (off_t)bloc_offset, SEEK_SET);
1224 written = ::write(fd, buf, count);
1226 // Write bitmap
1227 // FIXME if same extent_index as before we can skip bitmap read
1228 ::lseek(fd, (off_t)bitmap_offset, SEEK_SET);
1229 if (::read(fd, bitmap, dtoh32(header.specific.bitmap)) != (ssize_t)dtoh32(header.specific.bitmap))
1231 BX_PANIC(("redolog : failed to read bitmap for extent %d", extent_index));
1232 return 0;
1235 // If bloc does not belong to extent yet
1236 if (((bitmap[extent_offset/8] >> (extent_offset%8)) & 0x01) == 0x00)
1238 bitmap[extent_offset/8] |= 1 << (extent_offset%8);
1239 ::lseek(fd, (off_t)bitmap_offset, SEEK_SET);
1240 ::write(fd, bitmap, dtoh32(header.specific.bitmap));
1243 // Write catalog
1244 if (update_catalog)
1246 // FIXME if mmap
1247 catalog_offset = (Bit64s)STANDARD_HEADER_SIZE + (extent_index * sizeof(Bit32u));
1249 BX_DEBUG(("redolog : writing catalog at offset %x", (Bit32u)catalog_offset));
1251 ::lseek(fd, (off_t)catalog_offset, SEEK_SET);
1252 ::write(fd, &catalog[extent_index], sizeof(Bit32u));
1255 return written;
1258 /*** growing_image_t function definitions ***/
1260 growing_image_t::growing_image_t()
1262 redolog = new redolog_t();
1265 growing_image_t::~growing_image_t()
1267 delete redolog;
1270 int growing_image_t::open(const char* pathname)
1272 int filedes = redolog->open(pathname, REDOLOG_SUBTYPE_GROWING);
1273 hd_size = redolog->get_size();
1274 BX_INFO(("'growing' disk opened, growing file is '%s'", pathname));
1275 return filedes;
1278 void growing_image_t::close()
1280 redolog->close();
1283 Bit64s growing_image_t::lseek(Bit64s offset, int whence)
1285 return redolog->lseek(offset, whence);
1288 ssize_t growing_image_t::read(void* buf, size_t count)
1290 memset(buf, 0, count);
1291 redolog->read((char*) buf, count);
1292 return count;
1295 ssize_t growing_image_t::write(const void* buf, size_t count)
1297 return redolog->write((char*) buf, count);
1300 /*** undoable_image_t function definitions ***/
1302 undoable_image_t::undoable_image_t(const char* _redolog_name)
1304 redolog = new redolog_t();
1305 ro_disk = new default_image_t();
1306 redolog_name = NULL;
1307 if (_redolog_name != NULL) {
1308 if (strcmp(_redolog_name,"") != 0) {
1309 redolog_name = strdup(_redolog_name);
1314 undoable_image_t::~undoable_image_t()
1316 delete redolog;
1317 delete ro_disk;
1320 int undoable_image_t::open(const char* pathname)
1322 char *logname=NULL;
1324 if (ro_disk->open(pathname, O_RDONLY)<0)
1325 return -1;
1327 hd_size = ro_disk->hd_size;
1328 // if redolog name was set
1329 if (redolog_name != NULL) {
1330 if (strcmp(redolog_name, "") != 0) {
1331 logname = (char*)malloc(strlen(redolog_name) + 1);
1332 strcpy(logname, redolog_name);
1336 // Otherwise we make up the redolog filename from the pathname
1337 if (logname == NULL) {
1338 logname = (char*)malloc(strlen(pathname) + UNDOABLE_REDOLOG_EXTENSION_LENGTH + 1);
1339 sprintf(logname, "%s%s", pathname, UNDOABLE_REDOLOG_EXTENSION);
1342 if (redolog->open(logname,REDOLOG_SUBTYPE_UNDOABLE) < 0)
1344 if (redolog->create(logname, REDOLOG_SUBTYPE_UNDOABLE, hd_size) < 0)
1346 BX_PANIC(("Can't open or create redolog '%s'",logname));
1347 return -1;
1349 if (hd_size != redolog->get_size())
1351 BX_PANIC(("size reported by redolog doesn't match r/o disk size"));
1352 free(logname);
1353 return -1;
1357 BX_INFO(("'undoable' disk opened: ro-file is '%s', redolog is '%s'", pathname, logname));
1358 free(logname);
1360 return 0;
1363 void undoable_image_t::close ()
1365 redolog->close();
1366 ro_disk->close();
1368 if (redolog_name!=NULL)
1369 free(redolog_name);
1372 Bit64s undoable_image_t::lseek(Bit64s offset, int whence)
1374 redolog->lseek(offset, whence);
1375 return ro_disk->lseek(offset, whence);
1378 ssize_t undoable_image_t::read(void* buf, size_t count)
1380 // This should be fixed if count != 512
1381 if ((size_t)redolog->read((char*) buf, count) != count)
1382 return ro_disk->read((char*) buf, count);
1383 else
1384 return count;
1387 ssize_t undoable_image_t::write(const void* buf, size_t count)
1389 return redolog->write((char*) buf, count);
1392 /*** volatile_image_t function definitions ***/
1394 volatile_image_t::volatile_image_t(const char* _redolog_name)
1396 redolog = new redolog_t();
1397 ro_disk = new default_image_t();
1398 redolog_temp = NULL;
1399 redolog_name = NULL;
1400 if (_redolog_name != NULL) {
1401 if (strcmp(_redolog_name,"") != 0) {
1402 redolog_name = strdup(_redolog_name);
1407 volatile_image_t::~volatile_image_t()
1409 delete redolog;
1410 delete ro_disk;
1413 int volatile_image_t::open(const char* pathname)
1415 int filedes;
1416 const char *logname=NULL;
1418 if (ro_disk->open(pathname, O_RDONLY)<0)
1419 return -1;
1421 hd_size = ro_disk->hd_size;
1422 // if redolog name was set
1423 if (redolog_name != NULL) {
1424 if (strcmp(redolog_name, "") != 0) {
1425 logname = redolog_name;
1429 // otherwise use pathname as template
1430 if (logname == NULL) {
1431 logname = pathname;
1434 redolog_temp = (char*)malloc(strlen(logname) + VOLATILE_REDOLOG_EXTENSION_LENGTH + 1);
1435 sprintf (redolog_temp, "%s%s", logname, VOLATILE_REDOLOG_EXTENSION);
1437 filedes = mkstemp (redolog_temp);
1439 if (filedes < 0)
1441 BX_PANIC(("Can't create volatile redolog '%s'", redolog_temp));
1442 return -1;
1444 if (redolog->create(filedes, REDOLOG_SUBTYPE_VOLATILE, hd_size) < 0)
1446 BX_PANIC(("Can't create volatile redolog '%s'", redolog_temp));
1447 return -1;
1450 #if (!defined(WIN32)) && !BX_WITH_MACOS
1451 // on unix it is legal to delete an open file
1452 unlink(redolog_temp);
1453 #endif
1455 BX_INFO(("'volatile' disk opened: ro-file is '%s', redolog is '%s'", pathname, redolog_temp));
1457 return 0;
1460 void volatile_image_t::close()
1462 redolog->close();
1463 ro_disk->close();
1465 #if defined(WIN32) || BX_WITH_MACOS
1466 // on non-unix we have to wait till the file is closed to delete it
1467 unlink(redolog_temp);
1468 #endif
1469 if (redolog_temp!=NULL)
1470 free(redolog_temp);
1472 if (redolog_name!=NULL)
1473 free(redolog_name);
1476 Bit64s volatile_image_t::lseek(Bit64s offset, int whence)
1478 redolog->lseek(offset, whence);
1479 return ro_disk->lseek(offset, whence);
1482 ssize_t volatile_image_t::read(void* buf, size_t count)
1484 // This should be fixed if count != 512
1485 if ((size_t)redolog->read((char*) buf, count) != count)
1486 return ro_disk->read((char*) buf, count);
1487 else
1488 return count;
1491 ssize_t volatile_image_t::write(const void* buf, size_t count)
1493 return redolog->write((char*) buf, count);
1496 #if BX_COMPRESSED_HD_SUPPORT
1498 /*** z_ro_image_t function definitions ***/
1500 z_ro_image_t::z_ro_image_t()
1502 offset = (Bit64s)0;
1505 int z_ro_image_t::open(const char* pathname)
1507 fd = ::open(pathname, O_RDONLY
1508 #ifdef O_BINARY
1509 | O_BINARY
1510 #endif
1513 if (fd < 0)
1515 BX_PANIC(("Could not open '%s' file", pathname));
1516 return fd;
1519 gzfile = gzdopen(fd, "rb");
1520 return 0;
1523 void z_ro_image_t::close()
1525 if (fd > -1) {
1526 gzclose(gzfile);
1527 // ::close(fd);
1531 Bit64s z_ro_image_t::lseek(Bit64s _offset, int whence)
1533 // Only SEEK_SET supported
1534 if (whence != SEEK_SET)
1536 BX_PANIC(("lseek on compressed images : only SEEK_SET supported"));
1539 // Seeking is expensive on compressed files, so we do it
1540 // only when necessary, at the latest moment
1541 offset = _offset;
1543 return offset;
1546 ssize_t z_ro_image_t::read(void* buf, size_t count)
1548 gzseek(gzfile, offset, SEEK_SET);
1549 return gzread(gzfile, buf, count);
1552 ssize_t z_ro_image_t::write(const void* buf, size_t count)
1554 BX_PANIC(("z_ro_image: write not supported"));
1555 return 0;
1559 /*** z_undoable_image_t function definitions ***/
1561 z_undoable_image_t::z_undoable_image_t(Bit64u _size, const char* _redolog_name)
1563 redolog = new redolog_t();
1564 ro_disk = new z_ro_image_t();
1565 size = _size;
1567 redolog_name = NULL;
1568 if (_redolog_name != NULL) {
1569 if (strcmp(_redolog_name,"") != 0) {
1570 redolog_name = strdup(_redolog_name);
1575 z_undoable_image_t::~z_undoable_image_t()
1577 delete redolog;
1578 delete ro_disk;
1581 int z_undoable_image_t::open(const char* pathname)
1583 char *logname=NULL;
1585 if (ro_disk->open(pathname)<0)
1586 return -1;
1588 // If redolog name was set
1589 if (redolog_name != NULL) {
1590 if (strcmp(redolog_name, "") != 0) {
1591 logname = (char*)malloc(strlen(redolog_name) + 1);
1592 strcpy (logname, redolog_name);
1596 // Otherwise we make up the redolog filename from the pathname
1597 if (logname == NULL) {
1598 logname = (char*)malloc(strlen(pathname) + UNDOABLE_REDOLOG_EXTENSION_LENGTH + 1);
1599 sprintf (logname, "%s%s", pathname, UNDOABLE_REDOLOG_EXTENSION);
1602 if (redolog->open(logname, REDOLOG_SUBTYPE_UNDOABLE) < 0)
1604 if (redolog->create(logname, REDOLOG_SUBTYPE_UNDOABLE, size) < 0)
1606 BX_PANIC(("Can't open or create redolog '%s'",logname));
1607 return -1;
1611 BX_INFO(("'z-undoable' disk opened, z-ro-file is '%s', redolog is '%s'", pathname, logname));
1612 free(logname);
1614 return 0;
1617 void z_undoable_image_t::close()
1619 redolog->close();
1620 ro_disk->close();
1622 if (redolog_name!=NULL)
1623 free(redolog_name);
1626 Bit64s z_undoable_image_t::lseek(Bit64s offset, int whence)
1628 redolog->lseek(offset, whence);
1629 return ro_disk->lseek(offset, whence);
1632 ssize_t z_undoable_image_t::read(void* buf, size_t count)
1634 // This should be fixed if count != 512
1635 if (redolog->read((char*) buf, count) != count)
1636 return ro_disk->read((char*) buf, count);
1637 else
1638 return count;
1641 ssize_t z_undoable_image_t::write(const void* buf, size_t count)
1643 return redolog->write((char*) buf, count);
1647 /*** z_volatile_image_t function definitions ***/
1649 z_volatile_image_t::z_volatile_image_t(Bit64u _size, const char* _redolog_name)
1651 redolog = new redolog_t();
1652 ro_disk = new z_ro_image_t();
1653 size = _size;
1655 redolog_temp = NULL;
1656 redolog_name = NULL;
1657 if (_redolog_name != NULL) {
1658 if (strcmp(_redolog_name,"") != 0) {
1659 redolog_name = strdup(_redolog_name);
1664 z_volatile_image_t::~z_volatile_image_t()
1666 delete redolog;
1667 delete ro_disk;
1670 int z_volatile_image_t::open(const char* pathname)
1672 int filedes;
1673 const char *logname=NULL;
1675 if (ro_disk->open(pathname)<0)
1676 return -1;
1678 // if redolog name was set
1679 if (redolog_name != NULL) {
1680 if (strcmp(redolog_name, "") != 0) {
1681 logname = redolog_name;
1685 // otherwise use pathname as template
1686 if (logname == NULL) {
1687 logname = pathname;
1690 redolog_temp = (char*)malloc(strlen(logname) + VOLATILE_REDOLOG_EXTENSION_LENGTH + 1);
1691 sprintf (redolog_temp, "%s%s", logname, VOLATILE_REDOLOG_EXTENSION);
1693 filedes = mkstemp (redolog_temp);
1695 if (filedes < 0)
1697 BX_PANIC(("Can't create volatile redolog '%s'", redolog_temp));
1698 return -1;
1700 if (redolog->create(filedes, REDOLOG_SUBTYPE_VOLATILE, size) < 0)
1702 BX_PANIC(("Can't create volatile redolog '%s'", redolog_temp));
1703 return -1;
1706 #if (!defined(WIN32)) && !BX_WITH_MACOS
1707 // on unix it is legal to delete an open file
1708 unlink(redolog_temp);
1709 #endif
1711 BX_INFO(("'z-volatile' disk opened: z-ro-file is '%s', redolog is '%s'", pathname, redolog_temp));
1713 return 0;
1716 void z_volatile_image_t::close ()
1718 redolog->close();
1719 ro_disk->close();
1721 #if defined(WIN32) || BX_WITH_MACOS
1722 // on non-unix we have to wait till the file is closed to delete it
1723 unlink(redolog_temp);
1724 #endif
1726 if (redolog_temp!=NULL)
1727 free(redolog_temp);
1729 if (redolog_name!=NULL)
1730 free(redolog_name);
1733 Bit64s z_volatile_image_t::lseek(Bit64s offset, int whence)
1735 redolog->lseek(offset, whence);
1736 return ro_disk->lseek(offset, whence);
1739 ssize_t z_volatile_image_t::read (void* buf, size_t count)
1741 // This should be fixed if count != 512
1742 if (redolog->read((char*) buf, count) != count)
1743 return ro_disk->read((char*) buf, count);
1744 else
1745 return count;
1748 ssize_t z_volatile_image_t::write (const void* buf, size_t count)
1750 return redolog->write((char*) buf, count);
1753 #endif