diff --git a/samples/vboxwrapper/vbox.h b/samples/vboxwrapper/vbox.h
index f40bd6e982d1ed6f23210310967e438b701b1ddd..175756b12742d34390fb577ba68bda77893ed76e 100644
--- a/samples/vboxwrapper/vbox.h
+++ b/samples/vboxwrapper/vbox.h
@@ -54,6 +54,22 @@ struct VBOX_TIMESTAMP {
     int milliseconds;
 };
 
+// represents the state of a intermediate upload
+struct INTERMEDIATE_UPLOAD {
+    std::string file;
+    bool reported;
+    bool ignore;
+
+    INTERMEDIATE_UPLOAD() {
+        clear();
+    }
+    void clear() {
+        file = "";
+        reported = false;
+        ignore = false;
+    }
+};
+
 struct PORT_FORWARD {
     int host_port;      // 0 means assign dynamically
     int guest_port;
@@ -165,6 +181,8 @@ public:
     std::vector<std::string> trickle_trigger_files;
         // if find file of this name in shared/, send trickle-up message
         // with variety = filename, contents = file contents
+    std::vector<INTERMEDIATE_UPLOAD> intermediate_upload_files;
+        // if find file of this name in shared/, send specified file
     std::string completion_trigger_file;
         // if find this file in shared/, task is over.
         // File can optionally contain exit code (first line)
@@ -207,6 +225,7 @@ public:
     int pause();
     int resume();
     void check_trickle_triggers();
+    void check_intermediate_uploads();
     int create_snapshot(double elapsed_time);
     int cleanup_snapshots(bool delete_active);
     int restore_snapshot();
diff --git a/samples/vboxwrapper/vboxwrapper.cpp b/samples/vboxwrapper/vboxwrapper.cpp
index 9a1c814d33daffb76a2fb93de4fd4930f6ec297f..1d8f84dbe7e843dc88d5843bc062b484ce6da31d 100644
--- a/samples/vboxwrapper/vboxwrapper.cpp
+++ b/samples/vboxwrapper/vboxwrapper.cpp
@@ -162,6 +162,7 @@ int VBOX_VM::parse_port_forward(XML_PARSER& xp) {
 }
 
 int parse_job_file(VBOX_VM& vm) {
+    INTERMEDIATE_UPLOAD iu;
     MIOFILE mf;
     string str;
     char buf[1024], buf2[256];
@@ -215,6 +216,12 @@ int parse_job_file(VBOX_VM& vm) {
             vm.trickle_trigger_files.push_back(str);
             continue;
         }
+        else if (xp.parse_string("intermediate_upload_file", str)) {
+            iu.clear();
+            iu.file = str;
+            vm.intermediate_upload_files.push_back(iu);
+            continue;
+        }
         else if (xp.parse_string("completion_trigger_file", str)) {
             vm.completion_trigger_file = str;
             continue;
@@ -467,6 +474,45 @@ void VBOX_VM::check_trickle_triggers() {
     }
 }
 
+// check for intermediate upload files, and send them if found.
+//
+void VBOX_VM::check_intermediate_uploads() {
+    int retval;
+    char filename[256], path[MAXPATHLEN], buf[256];
+    for (unsigned int i=0; i<intermediate_upload_files.size(); i++) {
+        strcpy(filename, intermediate_upload_files[i].file.c_str());
+        sprintf(path, "shared/%s", filename);
+        if (!boinc_file_exists(path)) continue;
+        if (!intermediate_upload_files[i].reported && !intermediate_upload_files[i].ignore) {
+            fprintf(stderr,
+                "%s Reporting an intermediate file. (%s)\n",
+                vboxwrapper_msg_prefix(buf, sizeof(buf)),
+                intermediate_upload_files[i].file.c_str()
+            );
+            retval = boinc_upload_file(intermediate_upload_files[i].file);
+            if (retval) {
+                fprintf(stderr,
+                    "%s boinc_upload_file() failed: %s\n",
+                    vboxwrapper_msg_prefix(buf, sizeof(buf)), boincerror(retval)
+                );
+                intermediate_upload_files[i].ignore = true;
+            } else {
+                intermediate_upload_files[i].reported = true;
+            }
+        } else if (intermediate_upload_files[i].reported && !intermediate_upload_files[i].ignore) {
+            retval = boinc_upload_status(intermediate_upload_files[i].file);
+            if (!retval) {
+                fprintf(stderr,
+                    "%s Intermediate file uploaded. (%s)\n",
+                    vboxwrapper_msg_prefix(buf, sizeof(buf)),
+                    intermediate_upload_files[i].file.c_str()
+                );
+                intermediate_upload_files[i].ignore = true;
+            }
+        }
+    }
+}
+
 // see if it's time to send trickle-up reporting elapsed time
 //
 void check_trickle_period() {
@@ -1184,6 +1230,7 @@ int main(int argc, char** argv) {
             if ((loop_iteration % 10) == 0) {
                 current_cpu_time = starting_cpu_time + vm.get_vm_cpu_time();
                 vm.check_trickle_triggers();
+                vm.check_intermediate_uploads();
             }
 
             if (vm.job_duration) {