Index: services/file_service/file_service.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/services/services/file_service/Attic/file_service.inc,v
retrieving revision 1.1.2.7
diff -u -r1.1.2.7 file_service.inc
--- services/file_service/file_service.inc	15 Feb 2009 20:33:14 -0000	1.1.2.7
+++ services/file_service/file_service.inc	30 May 2009 20:42:24 -0000
@@ -12,7 +12,7 @@
  * @param $fid
  *   Number. File ID
  * @return
- *   Array. All elements from a given file
+ *   Array. All elements for a given file
  */
 function file_service_get($fid) {
   if ($file = db_fetch_array(db_query('SELECT * FROM {files} WHERE fid = %d', $fid))) {
@@ -40,6 +40,99 @@
   }
 }
 
+
+/**
+ * Check if the user has permission to save file information.
+ *
+ * Will probably want to revisit this down the road to make it
+ * somewhat tougher, esp if we get to the point where we're saving
+ * actual files (see below.)
+ */
+function file_service_save_access() {
+  return user_access('save file information');
+}
+
+/**
+ * Save file information.
+ *
+ * This is basically a copy of file_save_upload() from includes/file.inc
+ * without the upload-specific requirements. In D7 with File API this will
+ * be a lot easier to deal with. 
+ *
+ * @param $file
+ *   Array representing the file information
+ */
+function file_service_save($file) {
+  global $user;
+  $file = (object) $file;
+  
+  // If the file data is empty then bail
+  if (!isset($file->file)) {
+    return FALSE;
+  }
+  
+  // If the submitted file is an update, then set the update parameter for
+  // drupal_write_record(), indicating such. Otherwise we can just pass the
+  // object in and it will be treated as an insert.
+  $update = array();
+  if (!empty($file->fid)) {
+    $update = 'fid';
+  }
+
+  // Build the list of non-munged extensions.
+  // @todo: this should not be here. we need to figure out the right place.
+  // @todo: also isn't that repeated variable get a waste? I mean, I guess it
+  //        is cached but still it is pretty ugly.
+  $extensions = '';
+  foreach ($user->roles as $rid => $name) {
+    $extensions .= ' '. variable_get("upload_extensions_$rid",
+    variable_get('upload_extensions_default', 'jpg jpeg gif png txt html doc xls pdf ppt pps odt ods odp'));
+  }
+  
+  // Get the directory name for the location of the file:
+  $dir = dirname($file->filepath);
+  // Build the destination folder tree if it doesn't already exists.
+  if (!file_check_directory($dir, FILE_CREATE_DIRECTORY)) {
+    return services_error("Could not create destination directory for file.");
+  }
+
+  // Update file object as necessary
+  $file->filepath = file_destination(file_create_path($file->filepath), FILE_EXISTS_RENAME);
+  $file->filename = file_munge_filename(trim(basename($file->filepath), '.'), $extensions, TRUE);
+  $file->filemime = file_get_mimetype($file->filename);
+
+  // Rename potentially executable files, to help prevent exploits.
+  if (preg_match('/\.(php|pl|py|cgi|asp|js)$/i', $file->filename) && (substr($file->filename, -4) != '.txt')) {
+    $file->filemime = 'text/plain';
+    $file->filepath .= '.txt';
+    $file->filename .= '.txt';
+  }
+
+  // If the destination is not provided, or is not writable, error our
+  if (empty($file->filepath) || file_check_path($file->filepath) === FALSE) {
+    return services_error("Destintion directory does not exist or is not writeable.");
+  }
+
+  // Write the file
+  if (!file_save_data(base64_decode($file->file), $file->filepath .'/'. $file->filename)) {
+    return services_error("Could not write file to destination");
+  }
+
+  // If we made it this far it's safe to record this file in the database.
+  drupal_write_record('files', $file, $update);
+  
+  // hook_file_insert() requires an object
+  if (empty($update)) {
+    foreach (module_implements('file_insert') as $module) {
+      $function =  $module .'_file_insert';
+      $function($file);
+    }
+  }
+
+  // Return the fid
+  return $file->fid;
+}
+
 /**
  * Generates an array of base64 encoded files attached to a node
  *
Index: services/file_service/file_service.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/services/services/file_service/Attic/file_service.module,v
retrieving revision 1.1.2.7
diff -u -r1.1.2.7 file_service.module
--- services/file_service/file_service.module	18 May 2009 20:55:21 -0000	1.1.2.7
+++ services/file_service/file_service.module	30 May 2009 20:42:24 -0000
@@ -10,7 +10,7 @@
  * Implementation of hook_perm().
  */
 function file_service_perm() {
-  return array('get any binary files', 'get own binary files');
+  return array('get any binary files', 'get own binary files', 'save file information');
 }
 
 /**
@@ -51,6 +51,23 @@
       '#return'           => 'array',
       '#help'             => t('Returns the files attached to a node.')
     ),
+    
+    // file.save
+    array(
+      '#method'           => 'file.save',
+      '#callback'         => 'file_service_save',
+      '#access arguments' => 'save file information',
+      '#file'             => array('file' => 'inc', 'module' => 'file_service'),
+      '#args'             => array(
+        array(
+          '#name'           => 'file',
+          '#type'           => 'struct',
+          '#description'    => t('An object representing a file.'),
+        ),
+      ),
+      '#return'           => 'int',
+      '#help'             => t('Saves information about a specific file. Note this does not save files themselves, just the information as stored in the files table. Returns the fid of the new/updated file.'),
+    ),
   );
 }
 
