protected override void Run()
        {
            SafeToExit  = false;
            Description = Messages.ACTION_EXPORT_DESCRIPTION_IN_PROGRESS;

            RelatedTask = XenAPI.Task.create(Session,
                                             string.Format(Messages.ACTION_EXPORT_TASK_NAME, VM.Name),
                                             string.Format(Messages.ACTION_EXPORT_TASK_DESCRIPTION, VM.Name));

            UriBuilder uriBuilder = new UriBuilder(this.Session.Url);

            uriBuilder.Path  = "export";
            uriBuilder.Query = string.Format("session_id={0}&uuid={1}&task_id={2}",
                                             Uri.EscapeDataString(this.Session.uuid),
                                             Uri.EscapeDataString(this.VM.uuid),
                                             Uri.EscapeDataString(this.RelatedTask.opaque_ref));

            log.DebugFormat("Exporting {0} from {1} to {2}", VM.Name, uriBuilder.ToString(), _filename);

            // The DownloadFile call will block, so we need a separate thread to poll for task status.
            Thread taskThread = new Thread((ThreadStart)progressPoll);

            taskThread.Name         = "Progress polling thread for ExportVmAction for " + VM.Name.Ellipsise(20);
            taskThread.IsBackground = true;
            taskThread.Start();

            // Create the file with a temporary name till it is fully downloaded
            String tmpFile = _filename + ".tmp";

            try
            {
                HttpGet(tmpFile, uriBuilder.Uri);
            }
            catch (Exception e)
            {
                if (XenAPI.Task.get_status(this.Session, this.RelatedTask.opaque_ref) == XenAPI.task_status_type.pending &&
                    XenAPI.Task.get_progress(this.Session, this.RelatedTask.opaque_ref) == 0)
                {
                    // If task is pending and has zero progress, it probably hasn't been started,
                    // which probably means there was an exception in the GUI code before the
                    // action got going. Kill the task so that we don't block forever on
                    // taskThread.Join(). Brought to light by CA-11100.
                    XenAPI.Task.destroy(this.Session, this.RelatedTask.opaque_ref);
                }
                // Test for null: don't overwrite a previous exception
                if (_exception == null)
                {
                    _exception = e;
                }
            }

            taskThread.Join();

            using (FileStream fs = new FileStream(tmpFile, FileMode.Append))
            {
                // Flush written data to disk
                if (!Win32.FlushFileBuffers(fs.SafeFileHandle))
                {
                    Win32Exception exn = new Win32Exception(System.Runtime.InteropServices.Marshal.GetLastWin32Error());
                    log.ErrorFormat("FlushFileBuffers failed in ExportVmAction.\nNativeErrorCode={0}\nMessage={1}\nToString={2}",
                                    exn.NativeErrorCode, exn.Message, exn.ToString());
                }
            }

            if (verify && _exception == null)
            {
                long read     = 0;
                int  i        = 0;
                long filesize = new FileInfo(tmpFile).Length / 50; //Div by 50 to save doing the * 50 in the callback

                Export.verifyCallback callback = new Export.verifyCallback(delegate(uint size)
                {
                    read += size;
                    i++;

                    //divide number of updates by 10, so as not to spend all out time redrawing the control
                    //but try and send an update every second to keep the timer ticking
                    if (i > 10)
                    {
                        PercentComplete = 50 + (int)(read / filesize);
                        i = 0;
                    }
                });

                try
                {
                    using (FileStream fs = new FileStream(tmpFile, FileMode.Open, FileAccess.Read))
                    {
                        log.DebugFormat("Verifying export of {0} in {1}", VM.Name, _filename);
                        this.Description = Messages.ACTION_EXPORT_VERIFY;

                        export = new Export();
                        export.verify(fs, null, (Export.cancellingCallback) delegate() { return(Cancelling); }, callback);
                    }
                }
                catch (Exception e)
                {
                    if (_exception == null)
                    {
                        _exception = e;
                    }
                }
            }

            if (Cancelling || _exception is CancelledException)
            {
                log.InfoFormat("Export of VM {0} cancelled", VM.Name);
                this.Description = Messages.ACTION_EXPORT_DESCRIPTION_CANCELLED;

                log.DebugFormat("Deleting {0}", tmpFile);
                File.Delete(tmpFile);
                throw new CancelledException();
            }
            else if (_exception != null)
            {
                log.Warn(string.Format("Export of VM {0} failed", VM.Name), _exception);

                if (_exception is HeaderChecksumFailed || _exception is FormatException)
                {
                    this.Description = Messages.ACTION_EXPORT_DESCRIPTION_HEADER_CHECKSUM_FAILED;
                }
                else if (_exception is BlockChecksumFailed)
                {
                    this.Description = Messages.ACTION_EXPORT_DESCRIPTION_BLOCK_CHECKSUM_FAILED;
                }
                else if (_exception is IOException && Win32.GetHResult(_exception) == Win32.ERROR_DISK_FULL)
                {
                    this.Description = Messages.ACTION_EXPORT_DESCRIPTION_DISK_FULL;
                }
                else if (_exception is Failure && ((Failure)_exception).ErrorDescription[0] == Failure.VDI_IN_USE)
                {
                    this.Description = Messages.ACTION_EXPORT_DESCRIPTION_VDI_IN_USE;
                }
                else
                {
                    this.Description = Messages.ACTION_EXPORT_DESCRIPTION_FAILED;
                }

                var fi = new FileInfo(tmpFile);
                log.DebugFormat("Progress of the action until exception: {0}", PercentComplete);
                log.DebugFormat("Size file exported until exception: {0}", fi.Length);
                try
                {
                    using (Stream stream = new FileStream(tmpFile, FileMode.Open, FileAccess.Read))
                    {
                        ArchiveIterator iterator = ArchiveFactory.Reader(ArchiveFactory.Type.Tar,
                                                                         stream);
                        while (iterator.HasNext())
                        {
                            log.DebugFormat("Tar entry: {0} {1}", iterator.CurrentFileName(), iterator.CurrentFileSize());
                        }
                    }
                }
                catch (Exception)
                {}
                log.DebugFormat("Deleting {0}", tmpFile);
                File.Delete(tmpFile);
                throw new Exception(Description);
            }
            else
            {
                log.InfoFormat("Export of VM {0} successful", VM.Name);
                this.Description = Messages.ACTION_EXPORT_DESCRIPTION_SUCCESSFUL;

                log.DebugFormat("Renaming {0} to {1}", tmpFile, _filename);
                if (File.Exists(_filename))
                {
                    File.Delete(_filename);
                }
                File.Move(tmpFile, _filename);
            }
        }