diff --git a/samples/vboxwrapper/vbox_vboxmanage.cpp b/samples/vboxwrapper/vbox_vboxmanage.cpp
index dbf99abc32a..1580b1f43db 100644
--- a/samples/vboxwrapper/vbox_vboxmanage.cpp
+++ b/samples/vboxwrapper/vbox_vboxmanage.cpp
@@ -16,6 +16,7 @@
// along with BOINC. If not, see .
#ifdef _WIN32
+#include
#include "boinc_win.h"
#include "win_util.h"
#else
@@ -500,18 +501,80 @@ namespace vboxmanage {
// Adding virtual hard drive to VM
//
- vboxlog_msg("Adding virtual disk drive to VM. (%s)", image_filename.c_str());
+ string command_fix_part;
+
+ command_fix_part = "storageattach \"" + vm_name + "\" ";
+ command_fix_part += "--storagectl \"Hard Disk Controller\" ";
+ command_fix_part += "--port 0 ";
+ command_fix_part += "--device 0 ";
+ command_fix_part += "--type hdd ";
+
+ if (!multiattach_vdi_file.size()) {
+ // the traditional method:
+ // copy the vdi file from the projects dir to the slots dir and rename it vm_image.vdi
+ // each copy must get a new (random) UUID
+ //
+ vboxlog_msg("Adding virtual disk drive to VM. (%s)", image_filename.c_str());
+ command = command_fix_part;
+ command += "--setuuid \"\" ";
+ command += "--medium \"" + virtual_machine_slot_directory + "/" + image_filename + "\" ";
- command = "storageattach \"" + vm_name + "\" ";
- command += "--storagectl \"Hard Disk Controller\" ";
- command += "--port 0 ";
- command += "--device 0 ";
- command += "--type hdd ";
- command += "--setuuid \"\" ";
- command += "--medium \"" + virtual_machine_slot_directory + "/" + image_filename + "\" ";
+ retval = vbm_popen(command, output, "storage attach (fixed disk)");
+ if (retval) return retval;
+ } else {
+ // Use MultiAttach mode and differencing images
+ // See: https://www.virtualbox.org/manual/ch05.html#hdimagewrites
+ // https://www.virtualbox.org/manual/ch05.html#diffimages
+ // the vdi file downloaded to the projects dir becomes the parent (read only)
+ // "--setuid" must not be used
+ // each task gets it's own differencing image (writable)
+ // differencing images are written to the VM's snapshot folder
+ //
+ string medium_file = aid.project_dir;
+ medium_file += "/" + multiattach_vdi_file;
+
+#ifdef _WIN32
+ replace(medium_file.begin(), medium_file.end(), '\\', '/');
+#endif
+
+ vboxlog_msg("Adding virtual disk drive to VM. (%s)", multiattach_vdi_file.c_str());
+ command = "list hdds";
+
+ retval = vbm_popen(command, output, "check if parent hdd is registered", false, false);
+ if (retval) return retval;
+
+#ifdef _WIN32
+ replace(output.begin(), output.end(), '\\', '/');
+#endif
+
+ if (output.find(medium_file) == string::npos) {
+ // parent hdd is not registered
+ // vdi files can't be registered and set to multiattach mode within 1 step.
+ // They must first be attached to a VM in normal mode, then detached from the VM
+ //
+ command = command_fix_part;
+ command += "--medium \"" + medium_file + "\" ";
+
+ retval = vbm_popen(command, output, "register parent hdd", false, false);
+ if (retval) return retval;
+
+ command = command_fix_part;
+ command += "--medium none ";
+
+ retval = vbm_popen(command, output, "detach parent vdi", false, false);
+ if (retval) return retval;
+ // the vdi file is now registered and ready to be attached in multiattach mode
+ //
+ }
+
+ command = command_fix_part;
+ command += "--mtype multiattach ";
+ command += "--medium \"" + medium_file + "\" ";
+
+ retval = vbm_popen(command, output, "storage attach (fixed disk - multiattach mode)");
+ if (retval) return retval;
+ }
- retval = vbm_popen(command, output, "storage attach (fixed disk)");
- if (retval) return retval;
// Add guest additions to the VM
//
diff --git a/samples/vboxwrapper/vboxjob.cpp b/samples/vboxwrapper/vboxjob.cpp
index 73c7e0738f4..c1013aea37c 100644
--- a/samples/vboxwrapper/vboxjob.cpp
+++ b/samples/vboxwrapper/vboxjob.cpp
@@ -109,6 +109,7 @@ void VBOX_JOB::clear() {
heartbeat_filename.clear();
completion_trigger_file.clear();
temporary_exit_trigger_file.clear();
+ multiattach_vdi_file.clear();
enable_cern_dataformat = false;
enable_shared_directory = false;
enable_scratch_directory = false;
@@ -170,6 +171,7 @@ int VBOX_JOB::parse() {
else if (xp.parse_string("heartbeat_filename", heartbeat_filename)) continue;
else if (xp.parse_string("completion_trigger_file", completion_trigger_file)) continue;
else if (xp.parse_string("temporary_exit_trigger_file", temporary_exit_trigger_file)) continue;
+ else if (xp.parse_string("multiattach_vdi_file", multiattach_vdi_file)) continue;
else if (xp.parse_bool("enable_cern_dataformat", enable_cern_dataformat)) continue;
else if (xp.parse_bool("enable_network", enable_network)) continue;
else if (xp.parse_bool("network_bridged_mode", network_bridged_mode)) continue;
diff --git a/samples/vboxwrapper/vboxjob.h b/samples/vboxwrapper/vboxjob.h
index 3a4627b4971..d189685f803 100644
--- a/samples/vboxwrapper/vboxjob.h
+++ b/samples/vboxwrapper/vboxjob.h
@@ -166,6 +166,10 @@ class VBOX_JOB {
// File can optionally contain is_notice bool (second line)
// and stderr text (subsequent lines).
// Addresses a problem where VM doesn't shut down properly
+
+ std::string multiattach_vdi_file;
+ // Name of the vdi file (without path) to be attached in multiattach mode.
+ // The file is expected to be in the project's base directory.
};
#endif