- undoable: added support for checking the modification time of the base disk

- store r/o disk timestamp in FAT format in reserved field of redolog header
  - use the VVFAT function fat_datetime() to convert the mtime value
  - update redolog header if timestamp is undefined (first usage)
  - Bochs now panics if the r/o disk has been modified after the first usage with
    the undoable disk image mode to avoid journal file corruption.
- undoable: fixed r/o disk size check
This commit is contained in:
Volker Ruppert 2012-07-21 12:00:46 +00:00
parent b57ace2579
commit 8d30a38f7e
4 changed files with 58 additions and 11 deletions

View File

@ -159,6 +159,7 @@ int default_image_t::open(const char* pathname, int flags)
if (hFile != INVALID_HANDLE_VALUE) {
ULARGE_INTEGER FileSize;
FileSize.LowPart = GetFileSize(hFile, &FileSize.HighPart);
GetFileTime(hFile, NULL, NULL, &mtime);
CloseHandle(hFile);
if ((FileSize.LowPart != INVALID_FILE_SIZE) || (GetLastError() == NO_ERROR)) {
hd_size = FileSize.QuadPart;
@ -195,6 +196,7 @@ int default_image_t::open(const char* pathname, int flags)
{
hd_size = (Bit64u)stat_buf.st_size; // standard unix procedure to get size of regular files
}
mtime = stat_buf.st_mtime;
#endif
BX_INFO(("hd_size: "FMT_LL"u", hd_size));
if (hd_size <= 0) BX_PANIC(("size of disk image not detected / invalid"));
@ -224,6 +226,11 @@ ssize_t default_image_t::write(const void* buf, size_t count)
return ::write(fd, (char*) buf, count);
}
Bit32u default_image_t::get_timestamp()
{
return (fat_datetime(mtime, 1) | (fat_datetime(mtime, 0) << 16));
}
char increment_string(char *str, int diff)
{
// find the last character of the string, and increment it.
@ -1032,6 +1039,7 @@ int redolog_t::make_header(const char* type, Bit64u size)
else entries *= 2;
} while (maxsize < size);
header.specific.timestamp = 0;
header.specific.disk = htod64(size);
print_header();
@ -1201,6 +1209,20 @@ Bit64u redolog_t::get_size()
return dtoh64(header.specific.disk);
}
Bit32u redolog_t::get_timestamp()
{
return dtoh32(header.specific.timestamp);
}
bx_bool redolog_t::set_timestamp(Bit32u timestamp)
{
header.specific.timestamp = htod32(timestamp);
// Update header
::lseek(fd, 0, SEEK_SET);
::write(fd, &header, dtoh32(header.standard.header));
return 1;
}
Bit64s redolog_t::lseek(Bit64s offset, int whence)
{
if ((offset % 512) != 0) {
@ -1444,6 +1466,7 @@ undoable_image_t::~undoable_image_t()
int undoable_image_t::open(const char* pathname)
{
char *logname=NULL;
Bit32u timestamp1, timestamp2;
if (ro_disk->open(pathname, O_RDONLY)<0)
return -1;
@ -1463,19 +1486,27 @@ int undoable_image_t::open(const char* pathname)
sprintf(logname, "%s%s", pathname, UNDOABLE_REDOLOG_EXTENSION);
}
if (redolog->open(logname,REDOLOG_SUBTYPE_UNDOABLE) < 0)
{
if (redolog->create(logname, REDOLOG_SUBTYPE_UNDOABLE, hd_size) < 0)
{
if (redolog->open(logname,REDOLOG_SUBTYPE_UNDOABLE) < 0) {
if (redolog->create(logname, REDOLOG_SUBTYPE_UNDOABLE, hd_size) < 0) {
BX_PANIC(("Can't open or create redolog '%s'",logname));
return -1;
}
if (hd_size != redolog->get_size())
{
BX_PANIC(("size reported by redolog doesn't match r/o disk size"));
}
if (hd_size != redolog->get_size()) {
BX_PANIC(("size reported by redolog doesn't match r/o disk size"));
free(logname);
return -1;
}
timestamp1 = ro_disk->get_timestamp();
timestamp2 = redolog->get_timestamp();
if (timestamp2 != 0) {
if (timestamp1 != timestamp2) {
BX_PANIC(("unexpected modification time of the r/o disk"));
free(logname);
return -1;
}
} else if (timestamp1 != 0) {
redolog->set_timestamp(timestamp1);
}
BX_INFO(("'undoable' disk opened: ro-file is '%s', redolog is '%s'", pathname, logname));
@ -1484,7 +1515,7 @@ int undoable_image_t::open(const char* pathname)
return 0;
}
void undoable_image_t::close ()
void undoable_image_t::close()
{
redolog->close();
ro_disk->close();

View File

@ -78,7 +78,7 @@
Bit32u catalog; // #entries in the catalog
Bit32u bitmap; // bitmap size in bytes
Bit32u extent; // extent size in bytes
Bit32u reserved; // for data alignment
Bit32u timestamp; // modification time in FAT format (subtype 'undoable' only)
Bit64u disk; // disk size in bytes
} redolog_specific_header_t;
@ -182,8 +182,16 @@ class default_image_t : public device_image_t
// written (count).
ssize_t write(const void* buf, size_t count);
// Get modification time in FAT format
Bit32u get_timestamp();
private:
int fd;
#ifndef WIN32
time_t mtime;
#else
FILETIME mtime;
#endif
};
// CONCAT MODE
@ -349,6 +357,8 @@ class redolog_t
int open(const char* filename, const char* type);
void close();
Bit64u get_size();
Bit32u get_timestamp();
bx_bool set_timestamp(Bit32u timestamp);
Bit64s lseek(Bit64s offset, int whence);
ssize_t read(void* buf, size_t count);

View File

@ -487,7 +487,7 @@ static inline Bit8u fat_chksum(const direntry_t* entry)
// if return_time==0, this returns the fat_date, else the fat_time
#ifndef WIN32
static Bit16u fat_datetime(time_t time, int return_time)
Bit16u fat_datetime(time_t time, int return_time)
{
struct tm* t;
struct tm t1;
@ -499,7 +499,7 @@ static Bit16u fat_datetime(time_t time, int return_time)
return htod16((t->tm_mday) | ((t->tm_mon+1)<<5) | ((t->tm_year-80)<<9));
}
#else
static Bit16u fat_datetime(FILETIME time, int return_time)
Bit16u fat_datetime(FILETIME time, int return_time)
{
FILETIME localtime;
SYSTEMTIME systime;

View File

@ -106,6 +106,12 @@ typedef struct mapping_t {
int read_only;
} mapping_t;
#ifndef WIN32
Bit16u fat_datetime(time_t time, int return_time);
#else
Bit16u fat_datetime(FILETIME time, int return_time);
#endif
class vvfat_image_t : public device_image_t
{
public: