2013-10-14 00:30:51 +04:00
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2013 The Bochs Project
2018-03-31 00:04:04 +03:00
// Copyright (C) 2013-2018 Volker Ruppert
2013-10-14 00:30:51 +04:00
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
2013-10-20 01:16:10 +04:00
//
2013-11-03 11:41:29 +04:00
// Portions of this file contain code released under the following license.
2013-10-20 01:16:10 +04:00
//
// Connectix / Microsoft Virtual PC image creation code
//
// Copyright (c) 2005 Alex Beregszaszi
// Copyright (c) 2009 Kevin Wolf <kwolf@suse.de>
//
2013-11-03 11:41:29 +04:00
// VMDK version 4 image creation code
//
// Copyright (c) 2004 Fabrice Bellard
// Copyright (c) 2005 Filip Navara
//
2013-10-20 01:16:10 +04:00
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
/////////////////////////////////////////////////////////////////////////
2013-10-14 00:30:51 +04:00
2013-10-18 23:36:50 +04:00
// Create empty hard disk or floppy disk images for bochs.
2013-10-14 00:30:51 +04:00
// Convert a hard disk image from one format (mode) to another.
2013-10-18 23:36:50 +04:00
// Resize a hard disk image.
2013-10-14 00:30:51 +04:00
// Commit a redolog file to a supported base image.
2013-10-29 00:31:34 +04:00
# ifndef BXIMAGE
# define BXIMAGE
# endif
2013-10-17 20:00:26 +04:00
# include "config.h"
# include "bxcompat.h"
2013-11-01 22:19:52 +04:00
# if defined(WIN32) && !defined(__CYGWIN__)
2013-10-14 00:30:51 +04:00
# include <conio.h>
2013-10-16 23:33:30 +04:00
# include <winioctl.h>
2013-10-14 00:30:51 +04:00
# endif
# include <ctype.h>
2013-10-22 23:26:42 +04:00
# include "osdep.h"
# include "bswap.h"
2013-10-14 00:30:51 +04:00
# include "iodev/hdimage/hdimage.h"
# include "iodev/hdimage/vmware3.h"
# include "iodev/hdimage/vmware4.h"
# include "iodev/hdimage/vpc-img.h"
# define BXIMAGE_MODE_NULL 0
# define BXIMAGE_MODE_CREATE_IMAGE 1
# define BXIMAGE_MODE_CONVERT_IMAGE 2
2013-10-18 23:36:50 +04:00
# define BXIMAGE_MODE_RESIZE_IMAGE 3
# define BXIMAGE_MODE_COMMIT_UNDOABLE 4
2013-11-03 20:13:35 +04:00
# define BXIMAGE_MODE_IMAGE_INFO 5
2013-10-14 00:30:51 +04:00
2013-10-15 00:40:41 +04:00
# define BX_MAX_CYL_BITS 24 // 8 TB
const int bx_max_hd_megs = ( int ) ( ( ( 1 < < BX_MAX_CYL_BITS ) - 1 ) * 16.0 * 63.0 / 2048.0 ) ;
2013-10-27 23:23:59 +04:00
const char * hdimage_mode_names [ ] = {
" flat " ,
" concat " ,
" external " ,
" dll " ,
" sparse " ,
" vmware3 " ,
" vmware4 " ,
" undoable " ,
" growing " ,
" volatile " ,
" vvfat " ,
" vpc " ,
NULL
} ;
2013-10-14 00:30:51 +04:00
int bximage_mode ;
2013-10-15 00:40:41 +04:00
int bx_hdimage ;
int bx_fdsize_idx ;
2013-10-18 23:36:50 +04:00
int bx_min_hd_megs = 10 ;
2013-10-15 00:40:41 +04:00
int bx_hdsize ;
int bx_imagemode ;
2013-11-02 19:58:59 +04:00
int bx_backup ;
2013-10-14 00:30:51 +04:00
int bx_interactive ;
2018-03-31 00:04:04 +03:00
int bx_sectsize_idx ;
unsigned bx_sectsize_val ;
2013-10-14 00:30:51 +04:00
char bx_filename_1 [ 512 ] ;
char bx_filename_2 [ 512 ] ;
const char * EOF_ERR = " ERROR: End of input " ;
const char * svnid = " $Id$ " ;
const char * divider = " ======================================================================== " ;
const char * main_menu_prompt =
" \n "
" 1. Create new floppy or hard disk image \n "
" 2. Convert hard disk image to other format (mode) \n "
2013-10-18 23:36:50 +04:00
" 3. Resize hard disk image \n "
" 4. Commit 'undoable' redolog to base image \n "
2013-11-03 20:13:35 +04:00
" 5. Disk image info \n "
2013-10-14 00:30:51 +04:00
" \n "
" 0. Quit \n "
" \n "
" Please choose one " ;
2013-10-15 00:40:41 +04:00
// menu data for choosing floppy/hard disk
const char * fdhd_menu = " \n Do you want to create a floppy disk image or a hard disk image? \n Please type hd or fd. " ;
const char * fdhd_choices [ ] = { " fd " , " hd " } ;
int fdhd_n_choices = 2 ;
// menu data for choosing floppy size
2017-02-12 19:51:52 +03:00
const char * fdsize_menu = " \n Choose the size of floppy disk image to create. \n Please type 160k, 180k, 320k, 360k, 720k, 1.2M, 1.44M, 1.68M, 1.72M, or 2.88M. \n " ;
2013-10-15 00:40:41 +04:00
const char * fdsize_choices [ ] = { " 160k " , " 180k " , " 320k " , " 360k " , " 720k " , " 1.2M " , " 1.44M " , " 1.68M " , " 1.72M " , " 2.88M " } ;
const unsigned fdsize_sectors [ ] = { 320 , 360 , 640 , 720 , 1440 , 2400 , 2880 , 3360 , 3444 , 5760 } ;
int fdsize_n_choices = 10 ;
2013-10-14 00:30:51 +04:00
// menu data for choosing disk mode
2013-11-03 11:41:29 +04:00
const char * hdmode_menu = " \n What kind of image should I create? \n Please type flat, sparse, growing, vpc or vmware4. " ;
const char * hdmode_choices [ ] = { " flat " , " sparse " , " growing " , " vpc " , " vmware4 " } ;
const int hdmode_choice_id [ ] = { BX_HDIMAGE_MODE_FLAT , BX_HDIMAGE_MODE_SPARSE ,
BX_HDIMAGE_MODE_GROWING , BX_HDIMAGE_MODE_VPC ,
BX_HDIMAGE_MODE_VMWARE4 } ;
int hdmode_n_choices = 5 ;
2013-10-14 00:30:51 +04:00
2018-03-31 00:04:04 +03:00
// menu data for choosing hard disk sector size
const char * sectsize_menu = " \n Choose the size of hard disk sectors. \n Please type 512, 1024 or 4096. " ;
const char * sectsize_choices [ ] = { " 512 " , " 1024 " , " 4096 " } ;
int sectsize_n_choices = 3 ;
2013-10-14 00:30:51 +04:00
# if !BX_HAVE_SNPRINTF
# include <stdarg.h>
/* XXX use real snprintf */
/* if they don't have snprintf, just use sprintf */
int snprintf ( char * s , size_t maxlen , const char * format , . . . )
{
va_list arg ;
int done ;
va_start ( arg , format ) ;
done = vsprintf ( s , format , arg ) ;
va_end ( arg ) ;
return done ;
}
# endif /* !BX_HAVE_SNPRINTF */
# if !BX_HAVE_MKSTEMP
int bx_mkstemp ( char * tpl )
{
mktemp ( tpl ) ;
return : : open ( tpl , O_RDWR | O_CREAT | O_TRUNC
# ifdef O_BINARY
| O_BINARY
# endif
, S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP ) ;
}
# endif // !BX_HAVE_MKSTEMP
void myexit ( int code )
{
2013-11-01 22:19:52 +04:00
# if defined(WIN32) && !defined(__CYGWIN__)
2013-10-14 00:30:51 +04:00
printf ( " \n Press any key to continue \n " ) ;
getch ( ) ;
# endif
exit ( code ) ;
}
// stolen from main.cc
void bx_center_print ( FILE * file , const char * line , int maxwidth )
{
int imax ;
int i ;
imax = ( maxwidth - strlen ( line ) ) > > 1 ;
for ( i = 0 ; i < imax ; i + + ) fputc ( ' ' , file ) ;
fputs ( line , file ) ;
}
void print_banner ( )
{
printf ( " %s \n " , divider ) ;
2013-10-21 22:26:00 +04:00
bx_center_print ( stdout , " bximage \n " , 72 ) ;
bx_center_print ( stdout , " Disk Image Creation / Conversion / Resize and Commit Tool for Bochs \n " , 72 ) ;
2013-10-14 00:30:51 +04:00
bx_center_print ( stdout , svnid , 72 ) ;
printf ( " \n %s \n " , divider ) ;
}
// this is how we crash
void fatal ( const char * c )
{
printf ( " %s \n " , c ) ;
myexit ( 1 ) ;
}
/* check if the argument string is present in the list -
returns index on success , - 1 on failure . */
int get_menu_index ( char * arg , int n_choices , const char * choice [ ] )
{
int i ;
for ( i = 0 ; i < n_choices ; i + + ) {
if ( ! strcmp ( choice [ i ] , arg ) ) {
// matched, return the choice number
return i ;
}
}
return - 1 ;
}
// remove leading spaces, newline junk at end. returns pointer to
// cleaned string, which is between s0 and the null
char * clean_string ( char * s0 )
{
char * s = s0 ;
char * ptr ;
// find first nonblank
while ( isspace ( * s ) )
s + + ;
// truncate string at first non-alphanumeric
ptr = s ;
while ( isprint ( * ptr ) )
ptr + + ;
* ptr = 0 ;
return s ;
}
// returns 0 on success, -1 on failure. The value goes into out.
int ask_int ( const char * prompt , int min , int max , int the_default , int * out )
{
int n = max + 1 ;
char buffer [ 1024 ] ;
char * clean ;
int illegal ;
while ( 1 ) {
printf ( " %s " , prompt ) ;
printf ( " [%d] " , the_default ) ;
if ( ! fgets ( buffer , sizeof ( buffer ) , stdin ) )
return - 1 ;
clean = clean_string ( buffer ) ;
if ( strlen ( clean ) < 1 ) {
// empty line, use the default
* out = the_default ;
return 0 ;
}
illegal = ( 1 ! = sscanf ( buffer , " %d " , & n ) ) ;
if ( illegal | | n < min | | n > max ) {
fprintf ( stderr , " Your choice (%s) was not an integer between %d and %d. \n \n " ,
clean , min , max ) ;
} else {
// choice is okay
* out = n ;
return 0 ;
}
}
}
int ask_menu ( const char * prompt , int n_choices , const char * choice [ ] , int the_default , int * out )
{
char buffer [ 1024 ] ;
char * clean ;
int i ;
* out = - 1 ;
while ( 1 ) {
printf ( " %s " , prompt ) ;
printf ( " [%s] " , choice [ the_default ] ) ;
if ( ! fgets ( buffer , sizeof ( buffer ) , stdin ) )
return - 1 ;
clean = clean_string ( buffer ) ;
if ( strlen ( clean ) < 1 ) {
// empty line, use the default
* out = the_default ;
return 0 ;
}
for ( i = 0 ; i < n_choices ; i + + ) {
if ( ! strcmp ( choice [ i ] , clean ) ) {
// matched, return the choice number
* out = i ;
return 0 ;
}
}
printf ( " Your choice (%s) did not match any of the choices: \n " , clean ) ;
for ( i = 0 ; i < n_choices ; i + + ) {
if ( i > 0 ) printf ( " , " ) ;
printf ( " %s " , choice [ i ] ) ;
}
printf ( " \n " ) ;
}
}
int ask_yn ( const char * prompt , int the_default , int * out )
{
char buffer [ 16 ] ;
char * clean ;
* out = - 1 ;
while ( 1 ) {
printf ( " %s " , prompt ) ;
printf ( " [%s] " , the_default ? " yes " : " no " ) ;
if ( ! fgets ( buffer , sizeof ( buffer ) , stdin ) )
return - 1 ;
clean = clean_string ( buffer ) ;
if ( strlen ( clean ) < 1 ) {
// empty line, use the default
* out = the_default ;
return 0 ;
}
switch ( tolower ( clean [ 0 ] ) ) {
case ' y ' : * out = 1 ; return 0 ;
case ' n ' : * out = 0 ; return 0 ;
}
fprintf ( stderr , " Please type either yes or no. \n " ) ;
}
}
int ask_string ( const char * prompt , char * the_default , char * out )
{
char buffer [ 1024 ] ;
char * clean ;
printf ( " %s " , prompt ) ;
printf ( " [%s] " , the_default ) ;
if ( ! fgets ( buffer , sizeof ( buffer ) , stdin ) )
return - 1 ;
clean = clean_string ( buffer ) ;
if ( strlen ( clean ) < 1 ) {
// empty line, use the default
strcpy ( out , the_default ) ;
return 0 ;
}
strcpy ( out , clean ) ;
return 0 ;
}
device_image_t * init_image ( Bit8u image_mode )
{
device_image_t * hdimage = NULL ;
// instantiate the right class
switch ( image_mode ) {
case BX_HDIMAGE_MODE_FLAT :
2014-01-23 22:35:18 +04:00
hdimage = new flat_image_t ( ) ;
2013-10-14 00:30:51 +04:00
break ;
2013-10-25 23:10:09 +04:00
case BX_HDIMAGE_MODE_CONCAT :
hdimage = new concat_image_t ( ) ;
break ;
# ifdef WIN32
case BX_HDIMAGE_MODE_DLL_HD :
hdimage = new dll_image_t ( ) ;
break ;
# endif
2013-10-14 00:30:51 +04:00
case BX_HDIMAGE_MODE_SPARSE :
hdimage = new sparse_image_t ( ) ;
break ;
case BX_HDIMAGE_MODE_VMWARE3 :
hdimage = new vmware3_image_t ( ) ;
break ;
case BX_HDIMAGE_MODE_VMWARE4 :
hdimage = new vmware4_image_t ( ) ;
break ;
case BX_HDIMAGE_MODE_GROWING :
hdimage = new growing_image_t ( ) ;
break ;
case BX_HDIMAGE_MODE_VPC :
hdimage = new vpc_image_t ( ) ;
break ;
default :
fatal ( " unsupported disk image mode " ) ;
break ;
}
return hdimage ;
}
int create_image_file ( const char * filename )
{
2013-10-15 22:00:39 +04:00
int fd = open ( filename , O_WRONLY | O_CREAT | O_TRUNC
2013-10-14 00:30:51 +04:00
# ifdef O_BINARY
| O_BINARY
# endif
, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP
) ;
if ( fd < 0 ) {
fatal ( " ERROR: flat file is not writable " ) ;
}
return fd ;
}
2013-10-15 22:00:39 +04:00
void create_flat_image ( const char * filename , Bit64u size )
2013-10-14 00:30:51 +04:00
{
char buffer [ 512 ] ;
int fd = create_image_file ( filename ) ;
memset ( buffer , 0 , 512 ) ;
2013-10-15 00:40:41 +04:00
if ( bx_write_image ( fd , size - 512 , buffer , 512 ) ! = 512 )
2013-10-14 00:30:51 +04:00
fatal ( " ERROR: while writing block in flat file ! " ) ;
close ( fd ) ;
2013-10-15 22:00:39 +04:00
}
2013-10-14 00:30:51 +04:00
2013-10-15 22:00:39 +04:00
# ifdef WIN32
void create_flat_image_win32 ( const char * filename , Bit64u size )
{
2013-10-16 22:55:43 +04:00
HANDLE hFile ;
LARGE_INTEGER pos ;
DWORD dwCount , errCode ;
USHORT mode ;
char buffer [ 1024 ] ;
hFile = CreateFile ( filename , GENERIC_WRITE | GENERIC_READ , 0 , NULL , CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL ) ;
if ( hFile = = INVALID_HANDLE_VALUE ) {
// attempt to print an error
# ifdef HAVE_PERROR
sprintf ( buffer , " while opening '%s' for writing " , filename ) ;
perror ( buffer ) ;
# endif
fatal ( " ERROR: Could not write disk image " ) ;
}
SetLastError ( NO_ERROR ) ;
mode = COMPRESSION_FORMAT_DEFAULT ;
dwCount = 0 ;
memset ( buffer , 0 , 512 ) ;
WriteFile ( hFile , buffer , 512 , & dwCount , NULL ) ; // set the first sector to 0, Win98 doesn't zero out the file
// if there is a write at/over the end
DeviceIoControl ( hFile , FSCTL_SET_COMPRESSION , & mode , sizeof ( mode ) , NULL , 0 , & dwCount , NULL ) ;
pos . u . LowPart = ( unsigned long ) ( ( size - 512 ) ) ;
pos . u . HighPart = ( unsigned long ) ( ( size - 512 ) > > 32 ) ;
pos . u . LowPart = SetFilePointer ( hFile , pos . u . LowPart , & pos . u . HighPart , FILE_BEGIN ) ;
memset ( buffer , 0 , 512 ) ;
if ( ( pos . u . LowPart = = 0xffffffff & & GetLastError ( ) ! = NO_ERROR ) | |
! WriteFile ( hFile , buffer , 512 , & dwCount , NULL ) | | ( dwCount ! = 512 ) ) {
errCode = GetLastError ( ) ;
CloseHandle ( hFile ) ;
if ( errCode = = ERROR_DISK_FULL ) {
fatal ( " \n ERROR: Not enough space on disk for image! " ) ;
} else {
sprintf ( buffer , " \n ERROR: Disk image creation failed with error code %i! " , errCode ) ;
fatal ( buffer ) ;
}
}
CloseHandle ( hFile ) ;
2013-10-14 00:30:51 +04:00
}
2013-10-15 22:00:39 +04:00
# endif
2013-10-14 00:30:51 +04:00
2013-10-15 22:00:39 +04:00
void create_sparse_image ( const char * filename , Bit64u size )
2013-10-14 00:30:51 +04:00
{
Bit64u numpages ;
sparse_header_t header ;
size_t sizesofar ;
int padtopagesize ;
memset ( & header , 0 , sizeof ( header ) ) ;
header . magic = htod32 ( SPARSE_HEADER_MAGIC ) ;
header . version = htod32 ( SPARSE_HEADER_VERSION ) ;
header . pagesize = htod32 ( ( 1 < < 10 ) * 32 ) ; // Use 32 KB Pages - could be configurable
numpages = ( size / dtoh32 ( header . pagesize ) ) + 1 ;
header . numpages = htod32 ( ( Bit32u ) numpages ) ;
header . disk = htod64 ( size ) ;
if ( numpages ! = dtoh32 ( header . numpages ) ) {
fatal ( " ERROR: The disk image is too large for a sparse image! " ) ;
// Could increase page size here.
// But note this only happens at 128 Terabytes!
}
int fd = create_image_file ( filename ) ;
if ( bx_write_image ( fd , 0 , & header , sizeof ( header ) ) ! = sizeof ( header ) ) {
close ( fd ) ;
fatal ( " ERROR: The disk image is not complete - could not write header! " ) ;
}
Bit32u * pagetable = new Bit32u [ dtoh32 ( header . numpages ) ] ;
if ( pagetable = = NULL )
fatal ( " ERROR: The disk image is not complete - could not create pagetable! " ) ;
for ( Bit32u i = 0 ; i < dtoh32 ( header . numpages ) ; i + + )
pagetable [ i ] = htod32 ( SPARSE_PAGE_NOT_ALLOCATED ) ;
if ( bx_write_image ( fd , sizeof ( header ) , pagetable , 4 * dtoh32 ( header . numpages ) ) ! = ( int ) ( 4 * dtoh32 ( header . numpages ) ) ) {
close ( fd ) ;
fatal ( " ERROR: The disk image is not complete - could not write pagetable! " ) ;
}
delete [ ] pagetable ;
sizesofar = SPARSE_HEADER_SIZE + ( 4 * dtoh32 ( header . numpages ) ) ;
padtopagesize = dtoh32 ( header . pagesize ) - ( sizesofar & ( dtoh32 ( header . pagesize ) - 1 ) ) ;
Bit8u * padding = new Bit8u [ padtopagesize ] ;
memset ( padding , 0 , padtopagesize ) ;
2015-01-03 16:53:52 +03:00
2013-10-14 00:30:51 +04:00
if ( bx_write_image ( fd , sizesofar , padding , padtopagesize ) ! = padtopagesize ) {
close ( fd ) ;
fatal ( " ERROR: The disk image is not complete - could not write padding! " ) ;
}
delete [ ] padding ;
close ( fd ) ;
}
2013-10-15 22:00:39 +04:00
void create_growing_image ( const char * filename , Bit64u size )
2013-10-14 00:30:51 +04:00
{
redolog_t * redolog = new redolog_t ;
if ( redolog - > create ( filename , REDOLOG_SUBTYPE_GROWING , size ) < 0 )
fatal ( " Can't create growing mode image " ) ;
redolog - > close ( ) ;
delete redolog ;
2013-10-15 22:00:39 +04:00
}
2013-10-14 00:30:51 +04:00
2013-10-20 01:16:10 +04:00
void create_vpc_image ( const char * filename , Bit64u size )
{
Bit8u buf [ 1024 ] ;
Bit16u cyls = 0 ;
Bit8u heads = 16 , secs_per_cyl = 63 ;
Bit64u total_sectors ;
Bit64s offset ;
size_t block_size , num_bat_entries ;
int fd , i ;
total_sectors = size > > 9 ;
2013-10-22 23:26:42 +04:00
cyls = ( Bit16u ) ( size / heads / secs_per_cyl / 512.0 ) ;
2013-10-20 01:16:10 +04:00
vhd_footer_t * footer = ( vhd_footer_t * ) buf ;
memset ( footer , 0 , HEADER_SIZE ) ;
memcpy ( footer - > creator , " conectix " , 8 ) ;
// TODO Check if "bxic" creator_app is ok for VPC
memcpy ( footer - > creator_app , " bxic " , 4 ) ;
memcpy ( footer - > creator_os , " Wi2k " , 4 ) ;
footer - > features = be32_to_cpu ( 0x02 ) ;
footer - > version = be32_to_cpu ( 0x00010000 ) ;
footer - > data_offset = be64_to_cpu ( HEADER_SIZE ) ;
2013-10-22 23:26:42 +04:00
footer - > timestamp = be32_to_cpu ( ( Bit32u ) time ( NULL ) - VHD_TIMESTAMP_BASE ) ;
2013-10-20 01:16:10 +04:00
// Version of Virtual PC 2007
footer - > major = be16_to_cpu ( 0x0005 ) ;
footer - > minor = be16_to_cpu ( 0x0003 ) ;
footer - > orig_size = be64_to_cpu ( total_sectors * 512 ) ;
footer - > size = be64_to_cpu ( total_sectors * 512 ) ;
footer - > cyls = be16_to_cpu ( cyls ) ;
footer - > heads = heads ;
footer - > secs_per_cyl = secs_per_cyl ;
footer - > type = be32_to_cpu ( VHD_DYNAMIC ) ;
footer - > checksum = be32_to_cpu ( vpc_checksum ( buf , HEADER_SIZE ) ) ;
fd = create_image_file ( filename ) ;
// Write the footer (twice: at the beginning and at the end)
block_size = 0x200000 ;
2013-10-22 23:26:42 +04:00
num_bat_entries = ( size_t ) ( total_sectors + block_size / 512 ) / ( block_size / 512 ) ;
2013-10-20 01:16:10 +04:00
if ( bx_write_image ( fd , 0 , footer , HEADER_SIZE ) ! = HEADER_SIZE ) {
close ( fd ) ;
fatal ( " ERROR: The disk image is not complete - could not write footer! " ) ;
}
offset = 1536 + ( ( num_bat_entries * 4 + 511 ) & ~ 511 ) ;
if ( bx_write_image ( fd , offset , footer , HEADER_SIZE ) ! = HEADER_SIZE ) {
close ( fd ) ;
fatal ( " ERROR: The disk image is not complete - could not write footer! " ) ;
}
// Write the initial BAT
memset ( buf , 0xFF , 512 ) ;
offset = 3 * 512 ;
for ( i = 0 ; i < ( int ) ( num_bat_entries * 4 + 511 ) / 512 ; i + + ) {
if ( bx_write_image ( fd , offset , buf , 512 ) ! = 512 ) {
close ( fd ) ;
fatal ( " ERROR: The disk image is not complete - could not write BAT! " ) ;
}
offset + = 512 ;
}
vhd_dyndisk_header_t * header = ( vhd_dyndisk_header_t * ) buf ;
memset ( header , 0 , 1024 ) ;
memcpy ( header - > magic , " cxsparse " , 8 ) ;
/*
* Note : The spec is actually wrong here for data_offset , it says
* 0xFFFFFFFF , but MS tools expect all 64 bits to be set .
*/
header - > data_offset = be64_to_cpu ( 0xFFFFFFFFFFFFFFFFULL ) ;
header - > table_offset = be64_to_cpu ( 3 * 512 ) ;
header - > version = be32_to_cpu ( 0x00010000 ) ;
header - > block_size = be32_to_cpu ( block_size ) ;
header - > max_table_entries = be32_to_cpu ( num_bat_entries ) ;
header - > checksum = be32_to_cpu ( vpc_checksum ( buf , 1024 ) ) ;
if ( bx_write_image ( fd , 512 , header , 1024 ) ! = 1024 ) {
close ( fd ) ;
fatal ( " ERROR: The disk image is not complete - could not write header! " ) ;
}
close ( fd ) ;
}
2013-11-03 11:41:29 +04:00
void create_vmware4_image ( const char * filename , Bit64u size )
{
const int SECTOR_SIZE = 512 ;
const char desc_template [ ] =
" # Disk DescriptorFile \n "
" version=1 \n "
" CID=%x \n "
" parentCID=ffffffff \n "
" createType= \" monolithicSparse \" \n "
" \n "
" # Extent description \n "
" %s "
" \n "
" # The Disk Data Base \n "
" #DDB \n "
" \n "
" ddb.virtualHWVersion = \" 4 \" \n "
" ddb.geometry.cylinders = \" " FMT_LL " d \" \n "
" ddb.geometry.heads = \" 16 \" \n "
" ddb.geometry.sectors = \" 63 \" \n "
" ddb.adapterType = \" ide \" \n " ;
int fd , i ;
Bit64s offset , cyl ;
Bit32u tmp , grains , gt_size , gt_count , gd_size ;
Bit8u buffer [ SECTOR_SIZE ] ;
char desc_line [ 256 ] ;
_VM4_Header header ;
header . id [ 0 ] = ' K ' ;
header . id [ 1 ] = ' D ' ;
header . id [ 2 ] = ' M ' ;
header . id [ 3 ] = ' V ' ;
header . version = htod32 ( 1 ) ;
header . flags = htod32 ( 3 ) ;
header . total_sectors = htod64 ( size / SECTOR_SIZE ) ;
header . tlb_size_sectors = 128 ;
header . description_offset_sectors = 1 ;
header . description_size_sectors = 20 ;
header . slb_count = 512 ;
header . flb_offset_sectors = header . description_offset_sectors +
header . description_size_sectors ;
grains = ( Bit32u ) ( ( size / 512 + header . tlb_size_sectors - 1 ) / header . tlb_size_sectors ) ;
gt_size = ( ( header . slb_count * sizeof ( Bit32u ) ) + 511 ) > > 9 ;
gt_count = ( grains + header . slb_count - 1 ) / header . slb_count ;
gd_size = ( gt_count * sizeof ( Bit32u ) + 511 ) > > 9 ;
header . flb_copy_offset_sectors = header . flb_offset_sectors + gd_size + ( gt_size * gt_count ) ;
header . tlb_offset_sectors =
( ( header . flb_copy_offset_sectors + gd_size + ( gt_size * gt_count ) +
header . tlb_size_sectors - 1 ) / header . tlb_size_sectors ) *
header . tlb_size_sectors ;
header . tlb_size_sectors = htod64 ( header . tlb_size_sectors ) ;
header . description_offset_sectors = htod64 ( header . description_offset_sectors ) ;
header . description_size_sectors = htod64 ( header . description_size_sectors ) ;
header . slb_count = htod32 ( header . slb_count ) ;
header . flb_offset_sectors = htod64 ( header . flb_offset_sectors ) ;
header . flb_copy_offset_sectors = htod64 ( header . flb_copy_offset_sectors ) ;
header . tlb_offset_sectors = htod64 ( header . tlb_offset_sectors ) ;
header . check_bytes [ 0 ] = 0x0a ;
header . check_bytes [ 1 ] = 0x20 ;
header . check_bytes [ 2 ] = 0x0d ;
header . check_bytes [ 3 ] = 0x0a ;
memset ( buffer , 0 , SECTOR_SIZE ) ;
memcpy ( buffer , & header , sizeof ( _VM4_Header ) ) ;
fd = create_image_file ( filename ) ;
if ( bx_write_image ( fd , 0 , buffer , SECTOR_SIZE ) ! = SECTOR_SIZE ) {
close ( fd ) ;
fatal ( " ERROR: The disk image is not complete - could not write header! " ) ;
}
memset ( buffer , 0 , SECTOR_SIZE ) ;
offset = dtoh64 ( header . tlb_offset_sectors * SECTOR_SIZE ) - SECTOR_SIZE ;
if ( bx_write_image ( fd , offset , buffer , SECTOR_SIZE ) ! = SECTOR_SIZE ) {
close ( fd ) ;
fatal ( " ERROR: The disk image is not complete - could not write empty table! " ) ;
}
offset = dtoh64 ( header . flb_offset_sectors ) * SECTOR_SIZE ;
2013-11-03 20:13:35 +04:00
for ( i = 0 , tmp = ( Bit32u ) dtoh64 ( header . flb_offset_sectors ) + gd_size ; i < ( int ) gt_count ; i + + , tmp + = gt_size ) {
2013-11-03 11:41:29 +04:00
if ( bx_write_image ( fd , offset , & tmp , sizeof ( tmp ) ) ! = sizeof ( tmp ) ) {
close ( fd ) ;
fatal ( " ERROR: The disk image is not complete - could not write table! " ) ;
}
offset + = sizeof ( tmp ) ;
}
offset = dtoh64 ( header . flb_copy_offset_sectors ) * SECTOR_SIZE ;
2013-11-03 20:13:35 +04:00
for ( i = 0 , tmp = ( Bit32u ) dtoh64 ( header . flb_copy_offset_sectors ) + gd_size ; i < ( int ) gt_count ; i + + , tmp + = gt_size ) {
2013-11-03 11:41:29 +04:00
if ( bx_write_image ( fd , offset , & tmp , sizeof ( tmp ) ) ! = sizeof ( tmp ) ) {
close ( fd ) ;
fatal ( " ERROR: The disk image is not complete - could not write backup table! " ) ;
}
offset + = sizeof ( tmp ) ;
}
memset ( buffer , 0 , SECTOR_SIZE ) ;
cyl = ( Bit64u ) ( size / 16 / 63 / 512.0 ) ;
snprintf ( desc_line , 256 , " RW " FMT_LL " d SPARSE \" %s \" " , size / SECTOR_SIZE , filename ) ;
sprintf ( ( char * ) buffer , desc_template , ( Bit32u ) time ( NULL ) , desc_line , cyl ) ;
offset = dtoh64 ( header . description_offset_sectors ) * SECTOR_SIZE ;
if ( bx_write_image ( fd , offset , buffer , SECTOR_SIZE ) ! = SECTOR_SIZE ) {
close ( fd ) ;
fatal ( " ERROR: The disk image is not complete - could not write description! " ) ;
}
close ( fd ) ;
}
2013-10-15 22:00:39 +04:00
void create_hard_disk_image ( const char * filename , int imgmode , Bit64u size )
{
switch ( imgmode ) {
case BX_HDIMAGE_MODE_FLAT :
2013-10-16 22:55:43 +04:00
# ifndef WIN32
2013-10-15 22:00:39 +04:00
create_flat_image ( filename , size ) ;
2013-10-16 22:55:43 +04:00
# else
create_flat_image_win32 ( filename , size ) ;
# endif
2013-10-15 22:00:39 +04:00
break ;
case BX_HDIMAGE_MODE_GROWING :
create_growing_image ( filename , size ) ;
break ;
case BX_HDIMAGE_MODE_SPARSE :
create_sparse_image ( filename , size ) ;
break ;
2013-10-20 01:16:10 +04:00
case BX_HDIMAGE_MODE_VPC :
create_vpc_image ( filename , size ) ;
break ;
2013-11-03 11:41:29 +04:00
case BX_HDIMAGE_MODE_VMWARE4 :
create_vmware4_image ( filename , size ) ;
break ;
2013-10-15 22:00:39 +04:00
default :
fatal ( " image mode not implemented yet " ) ;
}
2013-10-14 00:30:51 +04:00
}
2013-10-18 23:36:50 +04:00
void convert_image ( int newimgmode , Bit64u newsize )
2013-10-14 00:30:51 +04:00
{
device_image_t * source_image , * dest_image ;
2013-10-25 23:10:09 +04:00
int mode = - 1 ;
2013-10-14 00:30:51 +04:00
Bit64u i , sc , s ;
char buffer [ 512 ] , null_sector [ 512 ] ;
bx_bool error = 0 ;
printf ( " \n " ) ;
memset ( null_sector , 0 , 512 ) ;
2013-10-25 23:10:09 +04:00
if ( newsize = = 0 ) {
if ( ! strncmp ( bx_filename_1 , " concat: " , 7 ) ) {
mode = BX_HDIMAGE_MODE_CONCAT ;
strcpy ( bx_filename_1 , & bx_filename_1 [ 7 ] ) ;
# ifdef WIN32
} else if ( ! strncmp ( bx_filename_1 , " dll: " , 4 ) ) {
mode = BX_HDIMAGE_MODE_DLL_HD ;
strcpy ( bx_filename_1 , & bx_filename_1 [ 4 ] ) ;
# endif
}
}
2014-03-23 13:19:44 +04:00
if ( access ( bx_filename_1 , F_OK ) < 0 ) {
fatal ( " source disk image doesn't exist " ) ;
}
2013-10-25 23:10:09 +04:00
if ( mode = = - 1 ) {
mode = hdimage_detect_image_mode ( bx_filename_1 ) ;
}
2013-10-27 23:23:59 +04:00
if ( mode = = BX_HDIMAGE_MODE_UNKNOWN ) {
2013-10-18 23:36:50 +04:00
fatal ( " source disk image mode not detected " ) ;
2013-10-27 23:23:59 +04:00
} else {
2013-11-03 20:13:35 +04:00
printf ( " source image mode = '%s' \n " , hdimage_mode_names [ mode ] ) ;
2013-10-27 23:23:59 +04:00
}
2013-10-14 00:30:51 +04:00
source_image = init_image ( mode ) ;
if ( source_image - > open ( bx_filename_1 , O_RDONLY ) < 0 )
fatal ( " cannot open source disk image " ) ;
2013-10-18 23:36:50 +04:00
if ( newsize > 0 ) {
create_hard_disk_image ( bx_filename_2 , newimgmode , newsize ) ;
} else {
create_hard_disk_image ( bx_filename_2 , newimgmode , source_image - > hd_size ) ;
}
2013-10-14 00:30:51 +04:00
dest_image = init_image ( newimgmode ) ;
if ( dest_image - > open ( bx_filename_2 ) < 0 )
fatal ( " cannot open destination disk image " ) ;
printf ( " \n Converting image file: [ 0%%] " ) ;
sc = source_image - > hd_size / 512 ;
s = 0 ;
for ( i = 0 ; i < source_image - > hd_size ; i + = 512 ) {
printf ( " \ x8 \ x8 \ x8 \ x8 \ x8%3d%%] " , ( int ) ( ( s + 1 ) * 100 / sc ) ) ;
fflush ( stdout ) ;
if ( source_image - > lseek ( i , SEEK_SET ) < 0 ) {
error = 1 ;
break ;
}
if ( ( source_image - > read ( buffer , 512 ) = = 512 ) & &
( memcmp ( buffer , null_sector , 512 ) ! = 0 ) ) {
if ( dest_image - > lseek ( i , SEEK_SET ) < 0 ) {
error = 1 ;
break ;
}
if ( dest_image - > write ( buffer , 512 ) < 0 ) {
error = 1 ;
break ;
}
}
s + + ;
}
source_image - > close ( ) ;
dest_image - > close ( ) ;
delete dest_image ;
delete source_image ;
if ( error ) {
fatal ( " image conversion failed " ) ;
} else {
printf ( " Done. \n " ) ;
}
}
2013-10-15 22:00:39 +04:00
void commit_redolog ( )
2013-10-14 00:30:51 +04:00
{
device_image_t * base_image ;
redolog_t * redolog ;
2013-10-23 12:35:21 +04:00
int ret ;
2013-10-14 00:30:51 +04:00
printf ( " \n " ) ;
2014-03-23 13:19:44 +04:00
if ( access ( bx_filename_1 , F_OK ) < 0 ) {
fatal ( " base disk image doesn't exist " ) ;
}
2013-10-14 00:30:51 +04:00
int mode = hdimage_detect_image_mode ( bx_filename_1 ) ;
if ( mode = = BX_HDIMAGE_MODE_UNKNOWN )
fatal ( " base disk image mode not detected " ) ;
base_image = init_image ( mode ) ;
if ( base_image - > open ( bx_filename_1 ) < 0 )
fatal ( " cannot open base disk image " ) ;
redolog = new redolog_t ;
if ( redolog - > open ( bx_filename_2 , REDOLOG_SUBTYPE_UNDOABLE ) < 0 )
fatal ( " Can't open redolog " ) ;
if ( ! coherency_check ( base_image , redolog ) )
fatal ( " coherency check failed " ) ;
2013-10-23 12:35:21 +04:00
ret = redolog - > commit ( base_image ) ;
2013-10-14 00:30:51 +04:00
base_image - > close ( ) ;
redolog - > close ( ) ;
delete base_image ;
delete redolog ;
2013-10-23 12:35:21 +04:00
if ( ret < 0 ) {
2013-10-14 00:30:51 +04:00
fatal ( " redolog commit failed " ) ;
} else {
2013-10-23 12:35:21 +04:00
printf ( " Done. \n \n " ) ;
2013-10-14 00:30:51 +04:00
}
}
void print_usage ( )
{
fprintf ( stderr ,
2013-10-21 22:26:00 +04:00
" Usage: bximage [options] [filename1] [filename2] \n \n "
2013-10-14 00:30:51 +04:00
" Supported options: \n "
2013-11-03 20:13:35 +04:00
" -mode=... operation mode (create, convert, resize, commit, info) \n "
2013-10-15 00:40:41 +04:00
" -fd=... create: floppy image with size code \n "
2013-10-18 23:36:50 +04:00
" -hd=... create/resize: hard disk image with size in megabytes (M) \n "
" or gigabytes (G) \n "
2013-10-14 00:30:51 +04:00
" -imgmode=... create/convert: hard disk image mode \n "
2018-03-31 00:04:04 +03:00
" -sectsize=... create: hard disk sector size \n "
2013-11-02 19:58:59 +04:00
" -b convert/resize: create a backup of the source image \n "
" commit: create backups of the base image and redolog file \n "
2013-10-14 00:30:51 +04:00
" -q quiet mode (don't prompt for user input) \n "
" --help display this help and exit \n \n "
" Other arguments: \n "
" filename1 create: new image file \n "
2013-10-18 23:36:50 +04:00
" convert/resize: source image file \n "
2013-10-14 00:30:51 +04:00
" commit: base image file \n "
2013-10-18 23:36:50 +04:00
" filename2 convert/resize: destination image file \n "
2013-10-14 00:30:51 +04:00
" commit: redolog (journal) file \n \n " ) ;
}
2013-10-15 00:40:41 +04:00
void set_default_values ( )
{
if ( bximage_mode = = BXIMAGE_MODE_CREATE_IMAGE ) {
if ( bx_hdimage = = - 1 ) {
bx_hdimage = 1 ;
bx_fdsize_idx = 6 ;
bx_interactive = 1 ;
}
if ( bx_hdimage = = 1 ) {
if ( bx_imagemode = = - 1 ) {
bx_imagemode = 0 ;
bx_interactive = 1 ;
}
if ( bx_hdsize = = 0 ) {
bx_hdsize = 10 ;
bx_interactive = 1 ;
}
} else {
if ( bx_fdsize_idx = = - 1 ) {
bx_fdsize_idx = 6 ;
bx_interactive = 1 ;
}
}
} else if ( bximage_mode = = BXIMAGE_MODE_CONVERT_IMAGE ) {
if ( bx_imagemode = = - 1 ) {
bx_imagemode = 0 ;
bx_interactive = 1 ;
}
2013-10-22 23:26:42 +04:00
} else if ( bximage_mode = = BXIMAGE_MODE_RESIZE_IMAGE ) {
if ( bx_hdsize = = 0 ) {
bx_interactive = 1 ;
}
2013-10-15 00:40:41 +04:00
}
}
2013-10-14 00:30:51 +04:00
int parse_cmdline ( int argc , char * argv [ ] )
{
int arg = 1 ;
int ret = 1 ;
int fnargs = 0 ;
2013-10-17 20:00:26 +04:00
char * suffix ;
2013-10-14 00:30:51 +04:00
bximage_mode = BXIMAGE_MODE_NULL ;
2013-10-15 00:40:41 +04:00
bx_hdimage = - 1 ;
bx_fdsize_idx = - 1 ;
bx_hdsize = 0 ;
bx_imagemode = - 1 ;
2013-11-02 19:58:59 +04:00
bx_backup = 0 ;
2013-10-14 00:30:51 +04:00
bx_interactive = 1 ;
2018-03-31 00:04:04 +03:00
bx_sectsize_idx = 0 ;
bx_sectsize_val = 512 ;
2013-10-14 00:30:51 +04:00
bx_filename_1 [ 0 ] = 0 ;
bx_filename_2 [ 0 ] = 0 ;
while ( ( arg < argc ) & & ( ret = = 1 ) ) {
// parse next arg
if ( ! strcmp ( " --help " , argv [ arg ] ) | | ! strncmp ( " /? " , argv [ arg ] , 2 ) ) {
print_usage ( ) ;
ret = 0 ;
}
else if ( ! strncmp ( " -mode= " , argv [ arg ] , 6 ) ) {
2013-10-19 14:20:37 +04:00
if ( bximage_mode ! = BXIMAGE_MODE_NULL ) {
printf ( " bximage mode already defined \n \n " ) ;
ret = 0 ;
} else if ( ! strcmp ( & argv [ arg ] [ 6 ] , " create " ) ) {
2013-10-14 00:30:51 +04:00
bximage_mode = BXIMAGE_MODE_CREATE_IMAGE ;
} else if ( ! strcmp ( & argv [ arg ] [ 6 ] , " convert " ) ) {
bximage_mode = BXIMAGE_MODE_CONVERT_IMAGE ;
2013-10-18 23:36:50 +04:00
} else if ( ! strcmp ( & argv [ arg ] [ 6 ] , " resize " ) ) {
bximage_mode = BXIMAGE_MODE_RESIZE_IMAGE ;
2013-10-14 00:30:51 +04:00
} else if ( ! strcmp ( & argv [ arg ] [ 6 ] , " commit " ) ) {
bximage_mode = BXIMAGE_MODE_COMMIT_UNDOABLE ;
2013-11-03 20:13:35 +04:00
} else if ( ! strcmp ( & argv [ arg ] [ 6 ] , " info " ) ) {
bximage_mode = BXIMAGE_MODE_IMAGE_INFO ;
2013-10-14 00:30:51 +04:00
} else {
printf ( " Unknown bximage mode '%s' \n \n " , & argv [ arg ] [ 6 ] ) ;
2013-10-19 14:20:37 +04:00
ret = 0 ;
2013-10-14 00:30:51 +04:00
}
}
2013-10-15 00:40:41 +04:00
else if ( ! strncmp ( " -fd= " , argv [ arg ] , 4 ) ) {
bx_hdimage = 0 ;
bx_fdsize_idx = get_menu_index ( & argv [ arg ] [ 4 ] , fdsize_n_choices , fdsize_choices ) ;
if ( bx_fdsize_idx < 0 ) {
printf ( " Unknown floppy image size: %s \n \n " , & argv [ arg ] [ 6 ] ) ;
ret = 0 ;
}
}
else if ( ! strncmp ( " -hd= " , argv [ arg ] , 4 ) ) {
bx_hdimage = 1 ;
bx_imagemode = 0 ;
2013-10-17 20:00:26 +04:00
bx_hdsize = ( int ) strtol ( & argv [ arg ] [ 4 ] , & suffix , 10 ) ;
if ( bx_hdsize < = 0 ) {
2013-10-15 00:40:41 +04:00
printf ( " Error in hard disk image size argument: %s \n \n " , & argv [ arg ] [ 4 ] ) ;
ret = 0 ;
2013-10-17 20:00:26 +04:00
} else if ( ! strcmp ( suffix , " G " ) ) {
bx_hdsize < < = 10 ;
2013-10-22 23:26:42 +04:00
} else if ( ( strlen ( suffix ) > 0 ) & & strcmp ( suffix , " M " ) ) {
2013-10-17 20:00:26 +04:00
printf ( " Error in hard disk image size suffix: %s \n \n " , & argv [ arg ] [ 4 ] ) ;
ret = 0 ;
}
2013-10-18 23:36:50 +04:00
if ( ( bx_hdsize < bx_min_hd_megs ) | | ( bx_hdsize > bx_max_hd_megs ) ) {
2013-10-15 00:40:41 +04:00
printf ( " Hard disk image size out of range \n \n " ) ;
ret = 0 ;
}
}
2013-10-14 00:30:51 +04:00
else if ( ! strncmp ( " -imgmode= " , argv [ arg ] , 9 ) ) {
2013-10-15 00:40:41 +04:00
bx_imagemode = get_menu_index ( & argv [ arg ] [ 9 ] , hdmode_n_choices , hdmode_choices ) ;
if ( bx_imagemode < 0 ) {
2013-10-14 00:30:51 +04:00
printf ( " Unknown image mode: %s \n \n " , & argv [ arg ] [ 9 ] ) ;
ret = 0 ;
}
}
2018-03-31 00:04:04 +03:00
else if ( ! strncmp ( " -sectsize= " , argv [ arg ] , 10 ) ) {
bx_sectsize_idx = get_menu_index ( & argv [ arg ] [ 10 ] , sectsize_n_choices , sectsize_choices ) ;
if ( bx_sectsize_idx < 0 ) {
printf ( " Unsupported hard disk sector size: %s \n \n " , & argv [ arg ] [ 10 ] ) ;
ret = 0 ;
} else {
bx_sectsize_val = atoi ( sectsize_choices [ bx_sectsize_idx ] ) ;
}
}
2013-11-02 19:58:59 +04:00
else if ( ! strcmp ( " -b " , argv [ arg ] ) ) {
bx_backup = 1 ;
2013-10-14 00:30:51 +04:00
}
else if ( ! strcmp ( " -q " , argv [ arg ] ) ) {
bx_interactive = 0 ;
}
else if ( argv [ arg ] [ 0 ] = = ' - ' ) {
printf ( " Unknown option: %s \n \n " , argv [ arg ] ) ;
ret = 0 ;
} else {
if ( fnargs = = 0 ) {
strcpy ( bx_filename_1 , argv [ arg ] ) ;
} else if ( fnargs = = 1 ) {
strcpy ( bx_filename_2 , argv [ arg ] ) ;
} else {
printf ( " Ignoring extra parameter: %s \n \n " , argv [ arg ] ) ;
}
fnargs + + ;
}
arg + + ;
}
if ( bximage_mode = = BXIMAGE_MODE_NULL ) {
bx_interactive = 1 ;
2013-10-15 00:40:41 +04:00
} else {
set_default_values ( ) ;
2013-10-20 11:30:36 +04:00
if ( fnargs < 1 ) {
2013-10-15 00:40:41 +04:00
bx_interactive = 1 ;
}
2013-10-20 11:30:36 +04:00
if ( ( bximage_mode = = BXIMAGE_MODE_COMMIT_UNDOABLE ) & & ( fnargs = = 1 ) ) {
snprintf ( bx_filename_2 , 256 , " %s%s " , bx_filename_1 , UNDOABLE_REDOLOG_EXTENSION ) ;
}
2013-10-14 00:30:51 +04:00
}
return ret ;
}
2013-10-15 22:00:39 +04:00
void image_overwrite_check ( const char * filename )
{
char buffer [ 512 ] ;
int fd = hdimage_open_file ( filename , O_RDONLY , NULL , NULL ) ;
if ( fd > = 0 ) {
close ( fd ) ;
int confirm ;
sprintf ( buffer , " \n The disk image '%s' already exists. Are you sure you want to replace it? \n Please type yes or no. " , filename ) ;
if ( ask_yn ( buffer , 0 , & confirm ) < 0 )
fatal ( EOF_ERR ) ;
if ( ! confirm )
fatal ( " ERROR: Aborted " ) ;
}
}
2013-10-18 23:36:50 +04:00
void check_image_names ( )
{
2013-11-02 19:58:59 +04:00
char backup_fname [ 512 ] ;
2013-10-18 23:36:50 +04:00
if ( ! strlen ( bx_filename_2 ) ) {
strcpy ( bx_filename_2 , bx_filename_1 ) ;
}
2013-11-02 19:58:59 +04:00
if ( ( ! strcmp ( bx_filename_1 , bx_filename_2 ) ) & & bx_backup ) {
snprintf ( backup_fname , 256 , " %s%s " , bx_filename_1 , " .orig " ) ;
if ( hdimage_copy_file ( bx_filename_1 , backup_fname ) ! = 1 )
fatal ( " backup of source image file failed " ) ;
} else if ( strcmp ( bx_filename_1 , bx_filename_2 ) ) {
image_overwrite_check ( bx_filename_2 ) ;
2013-10-18 23:36:50 +04:00
}
}
2013-10-19 14:20:37 +04:00
int get_image_mode_and_hdsize ( const char * filename , int * hdsize_megs )
{
device_image_t * source_image ;
int imgmode = hdimage_detect_image_mode ( filename ) ;
if ( imgmode = = BX_HDIMAGE_MODE_UNKNOWN )
fatal ( " source disk image mode not detected " ) ;
source_image = init_image ( imgmode ) ;
if ( source_image - > open ( bx_filename_1 , O_RDONLY ) < 0 ) {
fatal ( " cannot open source disk image " ) ;
} else {
* hdsize_megs = ( int ) ( source_image - > hd_size > > 20 ) ;
source_image - > close ( ) ;
}
return imgmode ;
}
2014-06-07 11:32:06 +04:00
int CDECL main ( int argc , char * argv [ ] )
2013-10-14 00:30:51 +04:00
{
2013-10-18 23:36:50 +04:00
char bochsrc_line [ 256 ] , prompt [ 80 ] , tmpfname [ 512 ] ;
2013-10-14 00:30:51 +04:00
int imgmode = 0 ;
2013-10-15 22:00:39 +04:00
Bit64u hdsize = 0 ;
2013-11-03 20:13:35 +04:00
device_image_t * hdimage ;
2013-10-14 00:30:51 +04:00
if ( ! parse_cmdline ( argc , argv ) )
myexit ( 1 ) ;
print_banner ( ) ;
if ( bx_interactive ) {
2013-11-03 20:13:35 +04:00
if ( ask_int ( main_menu_prompt , 0 , 5 , bximage_mode , & bximage_mode ) < 0 )
2013-10-14 00:30:51 +04:00
fatal ( EOF_ERR ) ;
2013-10-15 00:40:41 +04:00
set_default_values ( ) ;
2013-10-14 00:30:51 +04:00
switch ( bximage_mode ) {
case BXIMAGE_MODE_NULL :
myexit ( 0 ) ;
break ;
2013-10-14 19:57:10 +04:00
case BXIMAGE_MODE_CREATE_IMAGE :
2013-10-19 14:20:37 +04:00
printf ( " \n Create image \n " ) ;
2013-10-15 00:40:41 +04:00
if ( ask_menu ( fdhd_menu , fdhd_n_choices , fdhd_choices , bx_hdimage , & bx_hdimage ) < 0 )
fatal ( EOF_ERR ) ;
if ( bx_hdimage = = 0 ) { // floppy
if ( ask_menu ( fdsize_menu , fdsize_n_choices , fdsize_choices , bx_fdsize_idx , & bx_fdsize_idx ) < 0 )
fatal ( EOF_ERR ) ;
if ( ! strlen ( bx_filename_1 ) ) {
strcpy ( bx_filename_1 , " a.img " ) ;
}
if ( ask_string ( " \n What should be the name of the image? \n " , bx_filename_1 , bx_filename_1 ) < 0 )
fatal ( EOF_ERR ) ;
} else { // hard disk
if ( ask_menu ( hdmode_menu , hdmode_n_choices , hdmode_choices , bx_imagemode , & bx_imagemode ) < 0 )
fatal ( EOF_ERR ) ;
2018-03-31 00:04:04 +03:00
imgmode = hdmode_choice_id [ bx_imagemode ] ;
if ( ( imgmode = = BX_HDIMAGE_MODE_FLAT ) | |
( imgmode = = BX_HDIMAGE_MODE_SPARSE ) | |
( imgmode = = BX_HDIMAGE_MODE_GROWING ) ) {
if ( ask_menu ( sectsize_menu , sectsize_n_choices , sectsize_choices , bx_sectsize_idx , & bx_sectsize_idx ) < 0 )
fatal ( EOF_ERR ) ;
bx_sectsize_val = atoi ( sectsize_choices [ bx_sectsize_idx ] ) ;
} else if ( bx_sectsize_val ! = 512 ) {
fatal ( EOF_ERR ) ;
}
2013-10-18 23:36:50 +04:00
sprintf ( prompt , " \n Enter the hard disk size in megabytes, between %d and %d \n " ,
bx_min_hd_megs , bx_max_hd_megs ) ;
if ( ask_int ( prompt , bx_min_hd_megs , bx_max_hd_megs , bx_hdsize , & bx_hdsize ) < 0 )
2013-10-15 00:40:41 +04:00
fatal ( EOF_ERR ) ;
if ( ! strlen ( bx_filename_1 ) ) {
strcpy ( bx_filename_1 , " c.img " ) ;
}
if ( ask_string ( " \n What should be the name of the image? \n " , bx_filename_1 , bx_filename_1 ) < 0 )
fatal ( EOF_ERR ) ;
}
2013-10-14 19:57:10 +04:00
break ;
2013-10-14 00:30:51 +04:00
case BXIMAGE_MODE_CONVERT_IMAGE :
2013-10-19 14:20:37 +04:00
printf ( " \n Convert image \n " ) ;
2013-10-14 00:30:51 +04:00
if ( ! strlen ( bx_filename_1 ) ) {
strcpy ( bx_filename_1 , " c.img " ) ;
}
if ( ask_string ( " \n What is the name of the source image? \n " , bx_filename_1 , bx_filename_1 ) < 0 )
fatal ( EOF_ERR ) ;
if ( ! strlen ( bx_filename_2 ) ) {
2013-10-25 23:10:09 +04:00
strcpy ( tmpfname , bx_filename_1 ) ;
2013-10-14 00:30:51 +04:00
} else {
2013-10-18 23:36:50 +04:00
strcpy ( tmpfname , bx_filename_2 ) ;
2013-10-14 00:30:51 +04:00
}
2013-10-18 23:36:50 +04:00
if ( ask_string ( " \n What should be the name of the new image? \n " , tmpfname , bx_filename_2 ) < 0 )
2013-10-14 00:30:51 +04:00
fatal ( EOF_ERR ) ;
2013-10-15 00:40:41 +04:00
if ( ask_menu ( hdmode_menu , hdmode_n_choices , hdmode_choices , bx_imagemode , & bx_imagemode ) < 0 )
2013-10-14 00:30:51 +04:00
fatal ( EOF_ERR ) ;
2013-11-02 19:58:59 +04:00
if ( ! strcmp ( bx_filename_1 , bx_filename_2 ) ) {
if ( ask_yn ( " \n Should I create a backup of the source image \n " , 0 , & bx_backup ) < 0 )
fatal ( EOF_ERR ) ;
}
2013-10-14 00:30:51 +04:00
break ;
2013-10-18 23:36:50 +04:00
case BXIMAGE_MODE_RESIZE_IMAGE :
2013-10-19 14:20:37 +04:00
printf ( " \n Resize image \n " ) ;
2013-10-18 23:36:50 +04:00
if ( ! strlen ( bx_filename_1 ) ) {
strcpy ( bx_filename_1 , " c.img " ) ;
}
if ( ask_string ( " \n What is the name of the source image? \n " , bx_filename_1 , bx_filename_1 ) < 0 )
fatal ( EOF_ERR ) ;
if ( ! strlen ( bx_filename_2 ) ) {
2013-10-25 23:10:09 +04:00
strcpy ( tmpfname , bx_filename_1 ) ;
2013-10-18 23:36:50 +04:00
} else {
strcpy ( tmpfname , bx_filename_2 ) ;
}
if ( ask_string ( " \n What should be the name of the new image? \n " , tmpfname , bx_filename_2 ) < 0 )
fatal ( EOF_ERR ) ;
2013-10-19 14:20:37 +04:00
imgmode = get_image_mode_and_hdsize ( bx_filename_1 , & bx_min_hd_megs ) ;
2013-10-18 23:36:50 +04:00
sprintf ( prompt , " \n Enter the new hard disk size in megabytes, between %d and %d \n " ,
bx_min_hd_megs , bx_max_hd_megs ) ;
if ( bx_hdsize < bx_min_hd_megs ) bx_hdsize = bx_min_hd_megs ;
if ( ask_int ( prompt , bx_min_hd_megs , bx_max_hd_megs , bx_hdsize , & bx_hdsize ) < 0 )
fatal ( EOF_ERR ) ;
2013-11-02 19:58:59 +04:00
if ( ! strcmp ( bx_filename_1 , bx_filename_2 ) ) {
if ( ask_yn ( " \n Should I create a backup of the source image \n " , 0 , & bx_backup ) < 0 )
fatal ( EOF_ERR ) ;
}
2013-10-18 23:36:50 +04:00
break ;
2013-10-14 00:30:51 +04:00
case BXIMAGE_MODE_COMMIT_UNDOABLE :
2013-10-19 14:20:37 +04:00
printf ( " \n Commit redolog \n " ) ;
2013-10-14 00:30:51 +04:00
if ( ! strlen ( bx_filename_1 ) ) {
strcpy ( bx_filename_1 , " c.img " ) ;
}
if ( ask_string ( " \n What is the name of the base image? \n " , bx_filename_1 , bx_filename_1 ) < 0 )
fatal ( EOF_ERR ) ;
if ( ! strlen ( bx_filename_2 ) ) {
2013-10-18 23:36:50 +04:00
snprintf ( tmpfname , 256 , " %s%s " , bx_filename_1 , UNDOABLE_REDOLOG_EXTENSION ) ;
2013-10-14 00:30:51 +04:00
} else {
2013-10-18 23:36:50 +04:00
strcpy ( tmpfname , bx_filename_2 ) ;
2013-10-14 00:30:51 +04:00
}
2013-10-18 23:36:50 +04:00
if ( ask_string ( " \n What is the redolog name? \n " , tmpfname , bx_filename_2 ) < 0 )
2013-10-14 00:30:51 +04:00
fatal ( EOF_ERR ) ;
2013-11-02 19:58:59 +04:00
if ( ask_yn ( " \n Should I create a backup of base image and redolog \n " , 0 , & bx_backup ) < 0 )
2013-10-14 00:30:51 +04:00
fatal ( EOF_ERR ) ;
break ;
2013-11-03 20:13:35 +04:00
case BXIMAGE_MODE_IMAGE_INFO :
printf ( " \n Disk image info \n " ) ;
if ( ! strlen ( bx_filename_1 ) ) {
strcpy ( bx_filename_1 , " c.img " ) ;
}
if ( ask_string ( " \n What is the name of the image? \n " , bx_filename_1 , bx_filename_1 ) < 0 )
fatal ( EOF_ERR ) ;
break ;
2013-10-14 00:30:51 +04:00
default :
2013-10-21 22:26:00 +04:00
fatal ( " \n bximage: unknown mode " ) ;
2013-10-14 00:30:51 +04:00
}
}
2013-10-19 14:20:37 +04:00
switch ( bximage_mode ) {
case BXIMAGE_MODE_CREATE_IMAGE :
image_overwrite_check ( bx_filename_1 ) ;
if ( bx_hdimage = = 0 ) {
sprintf ( bochsrc_line , " floppya: image= \" %s \" , status=inserted " , bx_filename_1 ) ;
2015-01-26 00:24:13 +03:00
printf ( " \n Creating floppy image '%s' with %u sectors \n " , bx_filename_1 , fdsize_sectors [ bx_fdsize_idx ] ) ;
2013-10-19 14:20:37 +04:00
create_flat_image ( bx_filename_1 , fdsize_sectors [ bx_fdsize_idx ] * 512 ) ;
} else {
2013-10-25 23:10:09 +04:00
int heads = 16 , spt = 63 ;
2018-03-31 00:04:04 +03:00
if ( bx_sectsize_val = = 512 ) {
sprintf ( bochsrc_line , " ata0-master: type=disk, path= \" %s \" , mode=%s " ,
bx_filename_1 , hdmode_choices [ bx_imagemode ] ) ;
} else {
sprintf ( bochsrc_line , " ata0-master: type=disk, path= \" %s \" , mode=%s, sect_size=%d " ,
bx_filename_1 , hdmode_choices [ bx_imagemode ] , bx_sectsize_val ) ;
}
2013-10-19 14:20:37 +04:00
imgmode = hdmode_choice_id [ bx_imagemode ] ;
hdsize = ( ( Bit64u ) bx_hdsize ) < < 20 ;
2018-03-31 00:04:04 +03:00
Bit64u cyl = ( Bit64u ) ( hdsize / 16.0 / 63.0 / bx_sectsize_val ) ;
2013-10-19 14:20:37 +04:00
if ( cyl > = ( 1 < < BX_MAX_CYL_BITS ) )
fatal ( " ERROR: number of cylinders out of range ! \n " ) ;
2018-03-31 00:04:04 +03:00
printf ( " \n Creating hard disk image '%s' with CHS= " FMT_LL " d/%d/%d (sector size = %d) \n " ,
bx_filename_1 , cyl , heads , spt , bx_sectsize_val ) ;
hdsize = cyl * heads * spt * bx_sectsize_val ;
2013-10-19 14:20:37 +04:00
create_hard_disk_image ( bx_filename_1 , imgmode , hdsize ) ;
}
printf ( " \n The following line should appear in your bochsrc: \n " ) ;
printf ( " %s \n " , bochsrc_line ) ;
2013-10-15 22:00:39 +04:00
# ifdef WIN32
2013-10-19 14:20:37 +04:00
if ( OpenClipboard ( NULL ) ) {
HGLOBAL hgClip ;
EmptyClipboard ( ) ;
hgClip = GlobalAlloc ( GMEM_DDESHARE , ( strlen ( bochsrc_line ) + 1 ) ) ;
strcpy ( ( char * ) GlobalLock ( hgClip ) , bochsrc_line ) ;
GlobalUnlock ( hgClip ) ;
SetClipboardData ( CF_TEXT , hgClip ) ;
CloseClipboard ( ) ;
printf ( " (The line is stored in your windows clipboard, use CTRL-V to paste) \n " ) ;
}
2013-10-15 22:00:39 +04:00
# endif
2013-10-19 14:20:37 +04:00
break ;
case BXIMAGE_MODE_CONVERT_IMAGE :
check_image_names ( ) ;
imgmode = hdmode_choice_id [ bx_imagemode ] ;
convert_image ( imgmode , 0 ) ;
break ;
case BXIMAGE_MODE_RESIZE_IMAGE :
imgmode = get_image_mode_and_hdsize ( bx_filename_1 , & bx_min_hd_megs ) ;
if ( bx_hdsize < bx_min_hd_megs )
fatal ( " invalid image size " ) ;
hdsize = ( ( Bit64u ) bx_hdsize ) < < 20 ;
check_image_names ( ) ;
convert_image ( imgmode , hdsize ) ;
break ;
case BXIMAGE_MODE_COMMIT_UNDOABLE :
2013-11-02 19:58:59 +04:00
if ( bx_backup ) {
snprintf ( tmpfname , 256 , " %s%s " , bx_filename_1 , " .orig " ) ;
if ( hdimage_copy_file ( bx_filename_1 , tmpfname ) ! = 1 )
fatal ( " backup of base image file failed " ) ;
}
2013-10-19 14:20:37 +04:00
commit_redolog ( ) ;
2013-11-02 19:58:59 +04:00
if ( bx_backup ) {
snprintf ( tmpfname , 256 , " %s%s " , bx_filename_2 , " .orig " ) ;
if ( rename ( bx_filename_2 , tmpfname ) ! = 0 )
fatal ( " rename of redolog file failed " ) ;
} else {
2013-10-19 14:20:37 +04:00
if ( unlink ( bx_filename_2 ) ! = 0 )
fatal ( " ERROR: while removing the redolog ! \n " ) ;
}
break ;
2013-11-03 20:13:35 +04:00
case BXIMAGE_MODE_IMAGE_INFO :
imgmode = hdimage_detect_image_mode ( bx_filename_1 ) ;
if ( imgmode = = BX_HDIMAGE_MODE_UNKNOWN ) {
fatal ( " disk image mode not detected " ) ;
} else {
printf ( " \n disk image mode = '%s' \n " , hdimage_mode_names [ imgmode ] ) ;
}
hdimage = init_image ( imgmode ) ;
if ( hdimage - > open ( bx_filename_1 , O_RDONLY ) < 0 ) {
fatal ( " cannot open source disk image " ) ;
} else {
if ( hdimage - > get_capabilities ( ) & HDIMAGE_AUTO_GEOMETRY ) {
Bit64u cyl = ( Bit64u ) ( hdimage - > hd_size / 16.0 / 63.0 / 512.0 ) ;
2014-12-01 20:06:00 +03:00
printf ( " geometry = " FMT_LL " d/16/63 ( " FMT_LL " d MB) \n \n " , cyl ,
2013-11-03 20:13:35 +04:00
hdimage - > hd_size > > 20 ) ;
2014-04-20 16:50:05 +04:00
} else {
2014-12-01 20:06:00 +03:00
printf ( " geometry = %d/%d/%d ( " FMT_LL " d MB) \n \n " , hdimage - > cylinders ,
2014-04-20 16:50:05 +04:00
hdimage - > heads , hdimage - > spt , hdimage - > hd_size > > 20 ) ;
2013-11-03 20:13:35 +04:00
}
hdimage - > close ( ) ;
}
break ;
2013-10-14 00:30:51 +04:00
}
2013-10-15 22:00:39 +04:00
myexit ( 0 ) ;
2013-10-14 00:30:51 +04:00
return 0 ;
}