diff --git a/modules/upload_deploy/upload_deploy.info b/modules/upload_deploy/upload_deploy.info
new file mode 100644
index 0000000..19b45a1
--- /dev/null
+++ b/modules/upload_deploy/upload_deploy.info
@@ -0,0 +1,7 @@
+name = "Deploy Uploads"
+description = "Deploy uploaded file attachments using the Deployment framework"
+dependencies[] = deploy
+dependencies[] = deploy_uuid
+dependencies[] = upload
+package = Deployment
+core = 6.x
diff --git a/modules/upload_deploy/upload_deploy.module b/modules/upload_deploy/upload_deploy.module
new file mode 100644
index 0000000..62e04bb
--- /dev/null
+++ b/modules/upload_deploy/upload_deploy.module
@@ -0,0 +1,159 @@
+<?php
+/**
+ * @file
+ * Deployment API which enables modules to deploy items between servers.
+ *
+ * This module manages deployment-related issues for files added via the
+ * core upload module.
+ */
+
+/**
+ * Implementation of hook_nodeapi().
+ *
+ * Ensure new uploads are given a UUID.
+ */
+function upload_deploy_nodeapi(&$node, $op, $teaser) {
+  switch ($op) {
+    case 'insert':
+    case 'update':
+      if (isset($node->files)) {
+        foreach ($node->files as $fid => $file) {
+          if (!deploy_uuid_get_files_uuid($fid)) {
+            deploy_uuid_file_insert($file);
+          }
+        }
+      }
+      break;
+  }
+}
+
+/**
+ * Implementation of hook_deploy() on behalf of upload.module.
+ *
+ * This is a copy of filefield_deploy() that removes the dependency on
+ * field_file_load().
+ */
+function upload_deploy($fid) {
+  $file_info = db_fetch_array(db_query('SELECT f.* FROM {files} f WHERE f.fid = %d', $fid));
+  if (empty($file_info)) {
+    return xmlrpc_error($xmlrpcusererr + 1, t('File not found'));
+  }
+
+  // Save the base64_encode()d file into the file_info array for transfer
+  $filepath = file_create_path($file_info['filepath']);
+  $binaryfile = fopen($filepath, 'rb');
+  $filelength = filesize($filepath);
+  $file = base64_encode(fread($binaryfile, $filelength));
+  $file_info['file'] = $file;
+
+  // Normally, like with users and nodes, the uuid is added to the object in the 'load'
+  // op of their hook. Files have no load op, so we have to get it by hand.
+  $file_info['uuid'] = deploy_uuid_get_files_uuid($fid);
+  $remote_key = deploy_get_remote_key($file_info['uuid'], 'files');
+  $file_info['fid'] = isset($remote_key['fid']) ? $remote_key['fid'] : NULL;
+  
+  // If there is no remote file, then we also set the status to
+  // FILE_STATUS_TEMPORARY. If you don't do this, then Filefield
+  // will fail out with a validation error on the remote site. 
+  // It will get set to FILE_STATUS_PERMANENT when the node
+  // is saved.
+  if (isset($remote_key['fid'])) {
+    $file_info['fid'] = $remote_key['fid'];
+  }
+  else {
+    $file_info['fid'] = NULL;
+    $file_info['status'] = FILE_STATUS_TEMPORARY;
+  }
+  // The filefield service requires an object and I don't have time
+  // to go change all the above at the moment
+  $file_info = (object) $file_info;
+
+  // And we're off.
+  $fid = deploy_send(array('file.save'), array($file_info));
+
+  return $fid;
+}
+
+/**
+ * Implementation of hook_node_deploy_check().
+ *
+ * This is the dependency checking hook for nodes, called when
+ * a deployment has been requested that includes a node.
+ *
+ * @param $node
+ *   The node object being deployed
+ */
+function upload_deploy_node_deploy_check($node) {
+  $pid = variable_get('deploy_pid', 0);
+
+  if (variable_get("upload_$node->type", 1) == 1) {
+    if (!empty($node->files)) {
+      foreach ($node->files as $file) {
+        if (!deploy_item_is_in_plan($pid, 'upload', $file->fid)) {
+          // Does this file exist on the remote server?
+          $uuid = deploy_uuid_get_files_uuid($file->fid);
+          $remote_key = deploy_get_remote_key($uuid, 'files');
+
+          // If not we're going to add it to the deployment plan, with a weight
+          // of min(weight) - 1.
+          if (!$remote_key) {
+            deploy_add_to_plan($pid, 'upload', 'File: '. $file->filename, $file->fid, deploy_get_min_weight($pid)-1, DEPLOY_FILE_GROUP_WEIGHT);
+          }
+        }
+      }
+    }
+
+    // Ensure the list of files is sent after the node itself.
+    $weight = db_result(db_query("SELECT MAX(weight) FROM {deploy_plan_items} WHERE pid = %d", $pid));
+    deploy_add_to_plan($pid, 'node_uploads', 'Uploads: '. $node->title, $node->nid, $weight + 1, DEPLOY_NODE_GROUP_WEIGHT);
+  }
+}
+
+/**
+ * Implementation of hook_deploy(),
+ *
+ * @param $nid
+ *   Unique identifier for the node we're deploying.
+ * @return
+ *   The results of our xmlrpc call.
+ */
+function node_uploads_deploy($nid) {
+  // Bail if this node doesn't exist.
+  $node = node_load($nid);
+  if (empty($node)) {
+    return xmlrpc_error($xmlrpcusererr + 1, t('Node not found'));
+  }
+
+  // This should have been handled in Bail if this node doesn't exist.
+  $remote_key = deploy_get_remote_key($node->uuid, 'node');
+  if (!$remote_key) {
+    return xmlrpc_error($xmlrpcusererr + 1, t('Remote node not found'));
+  }
+  $remote_nid = $remote_key['nid'];
+
+  // Convert the fid of each file.
+  $files = array();
+  foreach ($node->files as $fid => $file) {
+    $file = (array) $file;
+    $file['uuid'] = deploy_uuid_get_files_uuid($fid);
+    $remote_key = deploy_get_remote_key($file['uuid'], 'files');
+    $file['fid'] = $remote_key['fid'];
+    $files[$file['fid']] = $file;
+  }
+  
+  // Send the files.
+  deploy_send(array('node.saveUploads'), array($remote_nid, $files));
+
+  return TRUE;
+}
+
+/**
+ * Implementation of hook_node_deploy(),
+ *
+ * @param $node
+ *   The node we're deploying.
+ */
+function upload_node_deploy($node) {
+  // This causes drupal_execute() to fail at the remote end, so we remove it.
+  unset($node->attach);
+}
\ No newline at end of file
diff --git a/services/upload_service/upload_service.inc b/services/upload_service/upload_service.inc
new file mode 100644
index 0000000..1ad9eb8
--- /dev/null
+++ b/services/upload_service/upload_service.inc
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ * Save upload attachments to a node.
+ *
+ * @param $nid
+ *   The node ID to use.
+ * @param $files
+ *   Array of files to attach.
+ */
+function upload_service_save($nid, $files) {
+  $node = node_load($nid);
+  
+  foreach ($files as $fid => &$file) {
+    // Create files that don't exist, update files that do.
+    $file['new'] = !isset($node->files[$fid]);
+    unset($node->files[$fid]);
+  }
+  
+  // Any remaining files need to be deleted.
+  foreach ($node->files as $fid => $file) {
+    $files[$fid] = array('remove' => TRUE);
+  }
+  
+  $node->files = $files;
+  upload_save($node);
+}
+
+/**
+ * Check if the user has the permission to save a node.
+ *
+ * @param $node
+ *   Object. The node object.
+ * @return
+ *   Boolean. TRUE if the user has the permission to save a node.
+ */
+function upload_service_save_access($nid, $files) {
+  $node = node_load($nid);
+  return node_access('update', $nid);
+}
diff --git a/services/upload_service/upload_service.info b/services/upload_service/upload_service.info
new file mode 100644
index 0000000..74833b5
--- /dev/null
+++ b/services/upload_service/upload_service.info
@@ -0,0 +1,5 @@
+name = Upload Service
+description = Provides a node attachment upload service.
+package = Services - services
+dependencies[] = node_service
+core = 6.x
diff --git a/services/upload_service/upload_service.module b/services/upload_service/upload_service.module
new file mode 100644
index 0000000..cf0fb5d
--- /dev/null
+++ b/services/upload_service/upload_service.module
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * Implementation of hook_service().
+ */
+function upload_service_service() {
+  return array(
+
+    // node.saveUploads
+    array(
+      '#method'           => 'node.saveUploads',
+      '#callback'         => 'upload_service_save',
+      '#access callback'  => 'upload_service_save_access',
+      '#file'             => array('file' => 'inc', 'module' => 'upload_service'),
+      '#args'             => array(
+        array(
+          '#name'           => 'nid',
+          '#type'           => 'int',
+          '#description'    => t('A node ID.')),
+        array(
+          '#name'           => 'files',
+          '#type'           => 'array',
+          '#description'    => t('A set of files to attach to a node.'))),
+      '#help'             => t('Attach file uploads to a node.')),
+  );
+}
